const 是 C 語言類型限定符,表示只讀。編譯器會阻止對其修改,提高代碼安全性與可讀性。
const int n = 5;
int a[n]; // ANSI C 錯誤:n 是「只讀變量」,非「編譯期常量」
5、'a'、枚舉常量、#define 宏。編譯期確定,存儲於只讀段。const int n。運行期分配內存,編譯器禁止寫入。const 變量不符合。C++ 則允許。
#define N 5 // 宏
enum { N = 5 }; // 枚舉常量 (推薦,有類型、作用域)
核心口訣:沿著 * 劃線,const 在左修飾指向的值,在右修飾指針本身。
const int* p; // p 指向 const int,值不可改,指針可改
int const* p; // 同義
const int* p = &x; // ok
*p = 10; // 錯誤
p = &y; // ok
int* const p = &x; // p 是常量指針,指針不可改,值可改
p = &y; // 錯誤
*p = 10; // ok
const int* const p = &x; // 指針與值均不可改
typedef char* pStr;
const pStr p2 = "hello"; // 等價於 char* const p2
// const 修飾的是 pStr (即 char*),所以指針不可改
p2++; // 錯誤
規則:有括號時,括號內是整體類型,const 修飾整體。
char* p = "hello"; // 危險:字面量在 .rodata,p 應為 const char*
p[0] = 'H'; // UB:段錯誤
const char* p = "hello"; // 正確:編譯器阻止修改
char arr[] = "hello"; // 正確:複製到棧數組,可修改
// 輸入參數:防止誤修改,接受字面量/常量實參
void print(const char* str);
void process(const BigStruct* s); // 避免拷貝大結構體
// 輸出參數:不加 const
void getResult(int* out);
const int ci = 10;
int* p = (int*)&ci; // 強制去 const
*p = 20; // UB:運行時可能崩潰或無效果 (取決於優化/存儲位置)
嚴禁 去除 const 後寫入,除非極少數硬體寄存器映射場景。
void foo(int arr[const]); // 等價於 int* const arr
void bar(int arr[static 10]); // 承諾至少 10 元素
void baz(const int arr[static 10]); // 只讀 + 至少 10 元素
| 聲明 | 含義 | 可修改指針 | 可修改值 |
|---|---|---|---|
const int* p | 指向常量的指針 | 是 | 否 |
int const* p | 同上 | 是 | 否 |
int* const p | 常量指針 | 否 | 是 |
const int* const p | 常量指針指向常量 | 否 | 否 |
const pStr p (pStr=char*) | 常量指針 | 否 | 是 |
const,除非需要修改。const char*。enum/#define 定義編譯期常量作為數組長度。typedef 陷阱:const pStr ≠ const char*。volatile,只讀寄存器用 const volatile。