核心差異:編譯期常量 vs 唯讀變量
| 特性 | C 語言 | C++ |
| 本質 | 唯讀變量(運行期分配記憶體) | 編譯期常量(進入符號表,不佔用存儲) |
| 取地址 | 強制分配臨時存儲,可取址 | 不取址則不分配存儲;取址時臨時分配 |
| 修改行為 | 通過指針修改屬未定義行為,但編譯器常不報錯 | 嚴格保護,修改導致段錯誤/編譯錯誤 |
| 作為陣列長度 | 不可(非常量表達式) | 可(const int n=10; int a[n]; 合法) |
| 外部連結 | 默認 extern | 默認 internal linkage(文件內部可見) |
代碼演示:C 語言可通過指針修改
// C code
const int a = 10;
int *p = (int*)&a;
*p = 11; // 編譯通過,運行時可能修改成功(視優化/硬體而定)
printf("%d", a); // 可能輸出 11 或 10
代碼演示:C++ 真常量特性
// C++ code
const int a = 10;
const int b = 11;
int arr[a + b]; // 合法:編譯期計算長度 21
// int *p = (int*)&a; // 編譯錯誤:不能將 const int* 轉為 int*
// *p = 11; // 未定義行為,現代編譯器直接報錯
記憶體模型視角
- C:
const int a 在 .rodata 或棧上分配,屬變量。
- C++:
const int a 編譯期替換為字面值,不佔用符號表條目(除非取址或 extern const)。
最佳實踐建議
- C++ 中優先用
constexpr (C++11) 明確編譯期常量。
- 跨語言介面(
extern "C")傳遞常量時,C++ 端用 extern const 確保連結一致性。
- 嵌入式開發需確認編譯器是否將
const 真正放入只讀段(.rodata),防止誤寫導致硬故障。