C23 的 constexpr(常數運算式)
/ KON-stek-spr /
在 C 裡,const 變數意味著「你不可修改它」,但它不一定是編譯期常數——例如你(在可移植的前提下)仍不能用 const int 當陣列大小或 case 標籤。C23 加入 constexpr,它宣告一個「物件」,其值是編譯期已知的真正常數運算式,所以可用在語言要求常數的任何地方。
你寫 constexpr int N = 16;,現在 N 是貨真價實的編譯期常數:它可以指定陣列大小、當 case 標籤、或餵給 static_assert,而編譯器保證它沒有執行期初始化。初始化子本身必須是常數運算式,型別限於適合的種類(整數、浮點數等;在 C23 中「不」包含一般使用者函式——C 的 constexpr 比 C++ 的窄得多,套用於物件而非函式)。把它想成舊有 #define 一個魔術數字習慣的具名、有型別替代品,但它尊重範圍與型別,並參與真正的型別檢查。
它重要在於用適當的具名型別取代易錯的前置處理器常數:constexpr double PI = 3.14159 有型別、遵守範圍、且會出現在除錯器中,這與 #define 不同。要記清楚的誠實提醒:在 C23,constexpr 套用於「物件」而非函式——C23 沒有像 C++ 那樣的 constexpr 函式,所以別期望把函式標成 constexpr 就讓它在編譯期執行。
constexpr int N = 16; int buf[N]; // 可行:N 是真正的編譯期常數 static_assert(N % 8 == 0, "N must be a multiple of 8"); constexpr double PI = 3.14159; // 有型別、有範圍——不像 #define PI ...
constexpr 命名一個有型別的編譯期常數,可用作陣列大小、case 標籤或 static_assert 的運算元。
C23 的 constexpr 套用於「物件」而非函式:它比 C++ 的 constexpr 窄得多,所以 C 裡沒有可在編譯期求值的 constexpr 函式。