型別
(另見算術型別以獲取大多數內建型別的詳細資訊,以及 C 庫提供的型別相關實用程式列表。)
物件、函式和表示式都具有一個稱為“型別”的屬性,它決定了儲存在物件中或由表示式計算的二進位制值的解釋方式。
目錄 |
[編輯] 型別分類
C 型別系統包含以下型別:
- 型別 void
- 基本型別
- 型別 char
- 有符號整數型別
- 標準:signed char, short, int, long, long long(C99 起)
|
(自 C23 起) |
|
(C99 起) |
- 無符號整數型別
- 標準:_Bool,(C99 起) unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long(C99 起)
|
(自 C23 起) |
|
(C99 起) |
- 浮點型別
- 實浮點型別:float, double, long double
|
(自 C23 起) |
|
(C99 起) |
- 派生型別
(C11 起) |
對於上面列出的每種型別,可能存在幾種限定版本,對應於 const
、volatile
和 restrict
限定符(在限定符語義允許的情況下)中的一個、兩個或所有三個的組合。
[編輯] 型別組
- 物件型別:所有非函式型別
- 字元型別:char, signed char, unsigned char
- 整數型別:char、有符號整數型別、無符號整數型別、列舉型別
- 實數型別:整數型別和實浮點型別
- 算術型別:整數型別和浮點型別
- 標量型別:算術型別、指標型別,和 nullptr_t(C23 起)
- 聚合型別:陣列型別和結構型別
- 派生宣告符型別:陣列型別、函式型別和指標型別
構造一個完整的物件型別,使其物件表示中的位元組數不能用型別 size_t(即 sizeof
運算子的結果型別)表示,包括在執行時形成這種可變長陣列型別,(C99 起)是未定義行為。
[編輯] 相容型別
在 C 程式中,在不同翻譯單元中引用同一物件或函式的宣告不必使用相同的型別。它們只需要使用足夠相似的型別,形式上稱為相容型別。這同樣適用於函式呼叫和左值訪問;引數型別必須與引數型別相容,左值表示式型別必須與訪問的物件型別相容。
型別 T
和 U
相容,如果
- 它們是相同的型別(相同的名稱或由
typedef
引入的別名) - 它們是相容的非限定型別的相同 cvr-限定版本
- 它們是指標型別,並且指向相容的型別
- 它們都是陣列型別,並且
- 它們的元素型別相容,並且
- 如果兩者都具有常量大小,則該大小相同。注意:未知邊界的陣列與任何具有相容元素型別的陣列相容。可變長陣列與任何具有相容元素型別的陣列相容。(C99 起)
- 它們都是結構/聯合/列舉型別,並且
- (C99)如果一個用標籤宣告,另一個也必須用相同的標籤宣告。
- 如果兩者都是完整型別,它們的成員必須在數量上完全對應,用相容型別宣告,並且具有匹配的名稱。
- 此外,如果它們是列舉,對應的成員也必須具有相同的值。
- 此外,如果它們是結構或聯合,
- 對應的成員必須以相同的順序宣告(僅限結構)
- 對應的位域必須具有相同的寬度。
- 一個是列舉型別,另一個是該列舉的底層型別
- 它們是函式型別,並且
- 它們的返回型別相容
- 它們都使用引數列表,引數數量(包括使用省略號)相同,並且對應的引數,在應用陣列到指標和函式到指標的型別調整並剝離頂級限定符後,具有相容型別
|
(直至 C23) |
型別 char 與 signed char 不相容,也與 unsigned char 不相容。
如果兩個宣告引用同一物件或函式且不使用相容型別,則程式的行為是未定義的。
// Translation Unit 1 struct S { int a; }; extern struct S *x; // compatible with TU2's x, but not with TU3's x // Translation Unit 2 struct S; extern struct S *x; // compatible with both x's // Translation Unit 3 struct S { float a; }; extern struct S *x; // compatible with TU2's x, but not with TU1's x // the behavior is undefined
// Translation Unit 1 #include <stdio.h> struct s { int i; }; // compatible with TU3's s, but not TU2's extern struct s x = {0}; // compatible with TU3's x extern void f(void); // compatible with TU2's f int main() { f(); return x.i; } // Translation Unit 2 struct s { float f; }; // compatible with TU4's s, but not TU1's s extern struct s y = {3.14}; // compatible with TU4's y void f() // compatible with TU1's f { return; } // Translation Unit 3 struct s { int i; }; // compatible with TU1's s, but not TU2's s extern struct s x; // compatible with TU1's x // Translation Unit 4 struct s { float f; }; // compatible with TU2's s, but not TU1's s extern struct s y; // compatible with TU2's y // the behavior is well-defined: only multiple declarations // of objects and functions must have compatible types, not the types themselves
注意:C++ 沒有相容型別的概念。在不同翻譯單元中宣告兩個相容但不相同的型別的 C 程式不是有效的 C++ 程式。
[編輯] 複合型別
複合型別可以由兩個相容的型別構造;它是一種與這兩個型別都相容並滿足以下條件的型別:
- 如果兩種型別都是陣列型別,則應用以下規則
- 如果一種型別是已知常量大小的陣列,則複合型別是該大小的陣列。
|
(C99 起) |
- 否則,兩種型別都是未知大小的陣列,複合型別是未知大小的陣列。
- 複合型別的元素型別是兩個元素型別的複合型別。
|
(直至 C23) |
- 如果兩種型別都是帶引數型別列表的函式型別,則複合引數型別列表中每個引數的型別是相應引數的複合型別。
這些規則遞迴應用於匯出這兩種型別的型別。
// Given the following two file scope declarations: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // C23: Error: conflicting types for 'f' // The resulting composite type for the function is: int f(int (*)(char *), double (*)[3]);
對於在先前宣告可見的作用域中宣告的具有內部或外部連結的識別符號,如果先前宣告指定了內部或外部連結,則後續宣告中的識別符號型別成為複合型別。
[編輯] 不完整型別
不完整型別是一種物件型別,它缺少足夠的資訊來確定該型別物件的大小。不完整型別可以在翻譯單元的某個點完成。
以下型別是不完整的
- 型別 void。此型別不能完成。
- 未知大小的陣列型別。它可以通過後續指定大小的宣告來完成。
extern char a[]; // the type of a is incomplete (this typically appears in a header) char a[10]; // the type of a is now complete (this typically appears in a source file)
- 未知內容的結構或聯合型別。它可以透過在同一作用域中定義其內容的相同結構或聯合的宣告來完成。
struct node { struct node* next; // struct node is incomplete at this point }; // struct node is complete at this point
[編輯] 型別名
型別可能需要在宣告以外的上下文中命名。在這些情況下,使用型別名,其語法與型別說明符和型別限定符列表完全相同,後跟宣告符(參見宣告),就像用於宣告此型別單個物件或函式一樣,只是省略了識別符號
int n; // declaration of an int sizeof(int); // use of type name int *a[3]; // declaration of an array of 3 pointers to int sizeof(int *[3]); // use of type name int (*p)[3]; // declaration of a pointer to array of 3 int sizeof(int (*)[3]); // use of type name int (*a)[*] // declaration of pointer to VLA (in a function parameter) sizeof(int (*)[*]) // use of type name (in a function parameter) int *f(void); // declaration of function sizeof(int *(void)); // use of type name int (*p)(void); // declaration of pointer to function sizeof(int (*)(void)); // use of type name int (*const a[])(unsigned int, ...) = {0}; // array of pointers to functions sizeof(int (*const [])(unsigned int, ...)); // use of type name
除了識別符號周圍的冗餘括號在型別名中是有意義的,並表示“無引數規範的函式”
int (n); // declares n of type int sizeof(int ()); // uses type "function returning int"
型別名用於以下情況
(C99 起) | |
(C11 起) |
型別名可以引入新型別
void* p = (void*)(struct X { int i; } *)0; // type name "struct X {int i;}*" used in the cast expression // introduces the new type "struct X" struct X x = {1}; // struct X is now in scope
[編輯] 參考資料
- C23 標準 (ISO/IEC 9899:2024)
- 6.2.5 Types (p: TBD)
- 6.2.6 Representations of types (p: TBD)
- 6.2.7 Compatible type and composite type (p: TBD)
- C17 標準 (ISO/IEC 9899:2018)
- 6.2.5 Types (p: 31-33)
- 6.2.6 Representations of types (p: 31-35)
- 6.2.7 Compatible type and composite type (p: 35-36)
- C11 標準 (ISO/IEC 9899:2011)
- 6.2.5 Types (p: 39-43)
- 6.2.6 Representations of types (p: 44-46)
- 6.2.7 Compatible type and composite type (p: 47-48)
- C99 標準 (ISO/IEC 9899:1999)
- 6.2.5 Types (p: 33-37)
- 6.2.6 Representations of types (p: 37-40)
- 6.2.7 Compatible type and composite type (p: 40-41)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.1.2.5 Types
- 3.1.2.6 Compatible type and composite type
[編輯] 另見
C++ 文件中的 型別
|