1. 程式人生 > >const 型別限定符——研讀C/C++標準

const 型別限定符——研讀C/C++標準

const 型別限定符

C 型別系統中每一個獨立的型別在都有數個該型別的限定版本,對應 constvolatile及對於指向物件指標的 restrict 限定符中的一個、兩個或全部三個。此頁面描述 const 限定符的效果。

編譯器可以把宣告帶 const 限定型別的物件放到只讀記憶體中,而且若程式決不取該 const 物件的地址,則可能完全不儲存它。

const 語義僅應用到左值表示式;只要在不要求左值的語境中使用 const 左值表示式,就會丟失其 const 限定符(注意不丟失 volatile 限定符,若它存在)。

指代 const 限定型別物件的左值表示式,和指代擁有至少一個 const 限定型別成員(包含為聚合體或聯合體所遞迴含有的成員)的結構體或聯合體的左值表示式,不是可修改左值。具體而言,它們不可賦值:

const int n = 1; // const 型別物件
n = 2; // 錯誤: n 的型別為 const 限定
 
int x = 2; // 無限定型別對下
const int* p = &x;
*p = 3; // 錯誤:左值 *p 的型別為 const 限定
 
struct {int a; const int b; } s1 = {.b=1}, s2 = {.b=2};
s1 = s2; // 錯誤: s1 的型別無限定,但它有 const 成員

cosnt 限定的結構體或聯合體型別的成員,取得它所屬型別的限定版本(在用 . 運算子或 -> 運算子訪問時)。

struct s { int i; const int ci; } s;
// s.i 的型別為 int , s.ci 的型別為 const int
const struct s cs;
// cs.i 和 cs.ci 的型別都是 const int

若以 const 型別限定符宣告陣列型別(通過使用 typedef ),則陣列型別無 const 限定,但其元素型別有。若以 const 型別限定符宣告函式型別(通過使用 typedef ),則行為未定義。

typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}}; // const int 的陣列的陣列
int* pi = a[0]; // 錯誤: a[0] 擁有 const int* 型別

const 限定的複合字面量不必指代相異的物件;能與恰好擁有重疊表示的其他複合字面量和字串字面量一同儲存它們。

const int* p1 = (const int[]){1, 2, 3};
const int* p2 = (const int[]){2, 3, 4}; // p2 的值可等於 p1+1
_Bool b = "foobar" + 3 == (const char[]){"bar"}; // b 的值可為 1    (C99 起)

指向非 const 型別的指標能隱式轉換成指向同一或相容型別的 const 限定版本的指標。能用轉型表示式進行逆向轉換。

int* p = 0;
const int* cp = p; // OK :新增限定符( int 到 const int )
p = cp; // 錯誤:捨棄限定符( const int 到 int )
p = (int*)cp; // OK :轉型

注意指向指向 T 指標的指標不可轉換為指向指向 const T 指標的指標;對於要相容的二個型別,其限定必須等同。

char *p = 0;
const char **cpp = &p; // 錯誤: char* 與 const char* 不是相容型別
char * const *pcp = &p; // OK :新增限定符( char * 到 char *const )

任何修改有 const 限定型別的物件的嘗試導致未定義行為。

const int n = 1; // const 限定型別物件
int* p = (int*)&n;
*p = 2; // 未定義行為

函式宣告中,關鍵詞 const 可出現在用於宣告陣列型別函式引數的方括號內。它限定陣列型別變換到的指標型別。

下列二個宣告宣告同一函式:

void f(double x[const], const double y[const]);
void f(double * const x, const double * const y); (C99起)

關鍵詞const

注意

C 從 C++ 接納了 const 限定符,但不同於 C++ 中, C 中 const 限定型別的表示式不是常量表達式;它們不可用作 case 標號,或用於初始化靜態和執行緒儲存期物件、用作列舉項或位域大小。以之為陣列大小是,產生的陣列為 VLA 。

引用

  • C11 standard (ISO/IEC 9899:2011):
    6.7.3 Type qualifiers (p: 121-123)
  • C99 standard (ISO/IEC 9899:1999):
    6.7.3 Type qualifiers (p: 108-110)
  • C89/C90 standard (ISO/IEC 9899:1990):
    3.5.3 Type qualifiers