楊志璿
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # constexpr and const *從 specifier 與 qualifier 概念出發* ## 前言 C++ 在過去數十年中,隨著編譯期常數(constant expressions)概念的引入,不斷充實並挑戰程式設計師對型別系統的認識。其中,`const` 與 `constexpr` 都扮演著確保資料不可變的重要角色,但兩者在設計目的、使用情境及語意上卻有著顯著差異。本篇文章將從語法與語意的角度出發,深入剖析兩者在陣列宣告中所呈現的微妙差別,並進一步探討 specifier 與 qualifier 這兩個術語的涵義與應用。 ## 1. 陣列宣告與基本語意解讀 ### 範例一:`const char *objTypes1[]` 這個宣告可以直譯為:「objTypes1 為一個陣列,其每個元素皆為指向常數字元(const char)的指標」。這裡的細節包括: - **指標內容不可變**:即使指標本身可以重新指向其他字串(例如 `objTypes1[0] = "abc";` 是允許的),但一旦某指標指向某字串,這個字串中的字元內容便不可被改變(例如 `objTypes1[0][0] = 'a';` 是禁忌)。 - **彈性與安全性**:這種宣告適用於需要在執行期動態調整指標,但希望保護底層資料不被修改的情境。 ### 範例二:`constexpr char *objTypes2[]` 與前例不同,此宣告引入了 `constexpr` specifier。由於 `constexpr` 要求初始化表達式在編譯期必須求值,因此我們可以這樣詮釋: > *「objTypes2 為一個陣列,其每個元素型態為指向 char 的指標,且整個陣列必須是 constant-initializable,同時享有 constant destruction 的特性」* 此處需注意的要點: - **編譯期常數**:所有陣列成員皆需在編譯期即被確定下來。這不僅要求指標不可變動,其所指的內容也必須是編譯期已確定的常數。 - **語意不協調問題**:由於字串常量的型態通常為 `const char *`(例如 `"123"`),將其用於初始化型態為 `char*` 的 constexpr 陣列便會造成型態不匹配,進而導致編譯錯誤。 - **未定義行為 (UB)**:任何試圖修改 constexpr 物件(例如透過 `objTypes2[0][0] = 'a';`)均會破壞該常數保證,而引發未定義行為。 ## 2. const 與 constexpr 的本質差異 ### const 的核心意涵 - **定義**:`const` 限定符表明所修飾的物件在其生命週期中不可被修改,但這個限定並未要求該物件在編譯期即必須有固定值。 - **使用情境**:常用於保護資料,以避免在執行期間的不慎修改。對於 `const char *`,語意上意味著「字串內容不可變」,而指標本身仍可變動。 ### constexpr 的深層涵義 - **定義**:`constexpr` 不僅要求物件不可在執行期間修改,更強制要求其值必須是編譯期可求值的常數。這代表整個物件在編譯期即被固化,並享有更嚴格的語義保證。 - **語意剖析**:在宣告中,`constexpr` 被視作一種 specifier,其作用遠超單純的型態修飾: - 它使物件成為編譯期常數(constant-initializable)。 - 強化了變數不可修改的保證,同時要求「常數消除 (constant destruction)」。 可以說,`constexpr` 擴展了 `const` 的功能,將焦點從執行期的不變性延伸到編譯期的確定性與安全性。 ## 3. specifier 與 qualifier:概念與範疇 在 C++ 中,許多語法元素都可歸納為 specifier 或 qualifier,而理解這兩者對於全面把握程式語意至關重要。 ### specifier - **定義與範圍**:specifier 為宣告提供額外的屬性與行為,例如 `constexpr`、`inline`、`static`、`extern`、`thread_local`。這些 specifier 不僅修飾型別,還影響變數的連結性、生命週期及初始化時機。 - **典型例子**:C23 中的 `auto` 同時扮演 storage specifier 與 type placeholder 的角色,進一步說明 specifier 的廣泛應用範圍。 ### qualifier - **定義與範疇**:qualifier 如 `const` 與 `volatile` 主要用來限制型別的操作,例如保證資料不被修改或避免過度優化。 - **相對局限性**:雖然 qualifier 為程式安全性提供保護,但其作用僅限於型別層面,並不影響物件的連結性或初始化機制。 這兩者在設計語言時各有所長,specifiers 提供的是一種更高層次的規範,而 qualifiers 則專注於型別本身的約束。理解這一點有助於我們在設計程式時作出更精確的選擇。 ## 4. 實例解析與常見陷阱 ### 案例比較 | 宣告方式 | 指標本身是否可修改 | 指標所指內容是否可修改 | 是否必須為編譯期常數 | | ---------------------------------------- | -------------------- | ----------------------- | -------------------- | | `const char *objTypes1[]` | ✔ | ✘ | ✘ | | `constexpr const char *objTypes2[]`* | ✘ | ✘ | ✔ | > *注意:正確的 constexpr 陣列範例應明確宣告指向常數字元,例如 `constexpr const char *objTypes2[] = {"123", "456", "789"};`。若僅寫作 `constexpr char *objTypes2[]`,由於初始化字串為常數,其型態不匹配將導致編譯錯誤。 ### 常見錯誤與陷阱 1. **型態不一致** 誤將 `constexpr char *` 與字串常量(本質上為 `const char *`)混用,容易在編譯期間遭遇型別錯誤。 2. **試圖修改 constexpr 物件** 由於 constexpr 保證了物件在編譯期即被固化,任何試圖修改(如 `objTypes2[0][0] = 'a';`)均違反此規範,導致未定義行為 (UB)。 3. **理解 specifier 與 qualifier 混淆** 忽略兩者在語意上的深層差異可能導致使用上出現邏輯錯誤,如錯誤假設 `constexpr` 只是一種「額外的 const 限定」,而非真正使物件於編譯期固定值。 ## 5. 小結與參考標準 總結而言,`const` 與 `constexpr` 均為 C++ 中保障程式不可變性的重要工具,但前者更偏重於執行期的安全保證,而後者則進一步要求編譯期常數的確定性。對於陣列宣告而言,正確理解兩者在語意上的差異,可以避免因型別不一致或未定義行為而導致的錯誤,從而撰寫出更加安全與高效的程式碼。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully