宣告
宣告 (Declaration) 是一種 C 語言結構,它將一個或多個 識別項 (identifiers) 引入程式中,並指定它們的含義與屬性。
宣告可以出現在任何作用域中。每個宣告都以分號結束(就像陳述式 (statement) 一樣),並由 兩個(直到 C23)三個(自 C23) 不同部分組成
指定符與限定符 (specifiers-and-qualifiers) 宣告子與初始化式 (declarators-and-initializers) (選用) ; |
(1) | ||||||||
屬性指定序列 (attr-spec-seq) 指定符與限定符 (specifiers-and-qualifiers) 宣告子與初始化式 (declarators-and-initializers) ; |
(2) | (C23 起) | |||||||
屬性指定序列 (attr-spec-seq) ; |
(3) | (C23 起) | |||||||
其中
| 指定符與限定符 (specifiers-and-qualifiers) | - | 以空白分隔的清單,順序不拘,包含:
|
| 宣告子與初始化式 (declarators-and-initializers) | - | 以逗號分隔的 宣告子 (declarators) 清單(每個宣告子提供額外的類型資訊及/或要宣告的識別項)。宣告子可搭配 初始化式 (initializers)。列舉 (enum)、結構 (struct) 與聯合 (union) 的宣告可以省略 宣告子,此時它們僅引入列舉常數及/或標記 (tags)。 |
| attr-spec-seq | - | (C23)選用的 屬性 (attributes) 清單,應用於被宣告的實體;若單獨出現則構成屬性宣告。 |
例如:
int a, *b=NULL; // "int" is the type specifier, // "a" is a declarator // "*b" is a declarator and NULL is its initializer const int *f(void); // "int" is the type specifier // "const" is the type qualifier // "*f(void)" is the declarator enum COLOR {RED, GREEN, BLUE} c; // "enum COLOR {RED, GREEN, BLUE}" is the type specifier // "c" is the declarator
宣告中引入的每個識別項之類型,是由 類型指定符 所指定的類型,與其 宣告子 所套用的類型修飾共同決定。若使用 auto 指定符,變數類型也可能會被推導。(自 C23)
屬性(自 C23) 可以出現在 指定符與限定符 中,此時它們會應用於由前述指定符所決定的類型上。
目錄 |
[編輯] 宣告子 (Declarators)
每個宣告子均為下列之一:
| 識別項 (identifier) 屬性指定序列 (attr-spec-seq) (選用) | (1) | ||||||||
( 宣告子 (declarator) ) |
(2) | ||||||||
* 屬性指定序列 (attr-spec-seq) (選用) 限定符 (qualifiers) (選用) 宣告子 (declarator) |
(3) | ||||||||
非指標宣告子 (noptr-declarator) [ static(選用) 限定符 (qualifiers) (選用) 運算式 (expression) ]非指標宣告子 (noptr-declarator) |
(4) | ||||||||
非指標宣告子 (noptr-declarator) ( 參數或識別項 (parameters-or-identifiers) ) |
(5) | ||||||||
此語法背後的邏輯是:當宣告子所宣告的識別項,以與該宣告子相同的形式出現在運算式中時,它將具有由類型指定符序列所指定的類型。
struct C { int member; // "int" is the type specifier // "member" is the declarator } obj, *pObj = &obj; // "struct C { int member; }" is the type specifier // declarator "obj" defines an object of type struct C // declarator "*pObj" declares a pointer to C, // initializer "= &obj" provides the initial value for that pointer int a = 1, *p = NULL, f(void), (*pf)(double); // the type specifier is "int" // declarator "a" defines an object of type int // initializer "=1" provides its initial value // declarator "*p" defines an object of type pointer to int // initializer "=NULL" provides its initial value // declarator "f(void)" declares a function taking void and returning int // declarator "(*pf)(double)" defines an object of type pointer // to function taking double and returning int int (*(*foo)(double))[3] = NULL; // the type specifier is int // 1. declarator "(*(*foo)(double))[3]" is an array declarator: // the type declared is "/nested declarator/ array of 3 int" // 2. the nested declarator is "*(*foo)(double))", which is a pointer declarator // the type declared is "/nested declarator/ pointer to array of 3 int" // 3. the nested declarator is "(*foo)(double)", which is a function declarator // the type declared is "/nested declarator/ function taking double and returning // pointer to array of 3 int" // 4. the nested declarator is "(*foo)" which is a (parenthesized, as required by // function declarator syntax) pointer declarator. // the type declared is "/nested declarator/ pointer to function taking double // and returning pointer to array of 3 int" // 5. the nested declarator is "foo", which is an identifier. // The declaration introduces the identifier "foo" to refer to an object of type // "pointer to function taking double and returning pointer to array of 3 int" // The initializer "= NULL" provides the initial value of this pointer. // If "foo" is used in an expression of the form of the declarator, its type would be // int. int x = (*(*foo)(1.2))[0];
不屬於其他宣告子的每個宣告子之結尾,均為一個 序列點 (sequence point)。
在所有情況下,屬性指定序列 均為選用的 屬性 序列(自 C23)。當出現在識別項之後時,它會應用於正被宣告的物件或函數。
[編輯] 定義 (Definitions)
定義 (definition) 是提供其所宣告識別項所有資訊的宣告。
對於函數,包含函數體的宣告即為 函數定義。
int foo(double); // declaration int foo(double x) { return x; } // definition
對於物件,配置儲存空間(自動或靜態,但不包含 extern)的宣告即為定義;而不配置儲存空間的宣告(外部宣告)則不是。
extern int n; // declaration int n = 10; // definition
對於 struct 與 union,指定成員清單的宣告即為定義。
struct X; // declaration struct X { int n; }; // definition
[編輯] 重宣告 (Redeclaration)
若在相同 作用域 (scope) 中,已存在相同識別項的先前宣告,則宣告無法再次引入該識別項,除非:
- 具連結性 (with linkage)(外部或內部)的物件宣告可以重複。
extern int x; int x = 10; // OK extern int x; // OK static int n; static int n = 10; // OK static int n; // OK
- 非 VLA 的 typedef 只要命名為相同的類型即可重複。
typedef int int_t; typedef int int_t; // OK
struct X; struct X { int n; }; struct X;
這些規則簡化了標頭檔的使用。
[編輯] 附註 (Notes)
|
在 C89 中,任何 複合陳述式 (compound statement)(區塊作用域)內的宣告必須出現在區塊的開頭,即所有 陳述式 之前。 此外,在 C89 中,回傳 int 的函數可由 函數呼叫運算子 隱含宣告,且在使用舊式 函數定義 時,類型為 int 的函數參數不需要宣告。 |
(直到 C99) |
禁止空白宣告子;簡單宣告必須至少有一個宣告子,或宣告至少一個 struct/union/enum 標記,或引入至少一個列舉常數。
|
若宣告子的任何部分是 變動長度陣列 (VLA) 宣告子,則整個宣告子的類型稱為「變動修改類型 (variably-modified type)」。由變動修改類型定義的類型也屬於變動修改類型 (VM)。 任何變動修改類型的宣告只能出現在 區塊作用域 或函數原型作用域中,且不能是 struct 或 union 的成員。儘管 VLA 只能具有自動或分配的 儲存持續期,但 VM 類型(例如 VLA 指標)可以是靜態的。對於 VM 類型的使用還有其他限制,請參閱 goto、switch 與 longjmp。 |
(自 C99 起) |
|
就 C 語法而言,static_assert 被視為宣告(因此它們可以出現在宣告可出現的任何地方),但它們不引入任何識別項,也不遵循宣告語法。 |
(自 C11 起) |
|
屬性宣告也被視為宣告(因此它們可以出現在宣告可出現的任何地方),但它們不引入任何識別項。不帶 屬性指定序列 的單一 |
(C23 起) |
[編輯] 參考資料 (References)
- C23 標準 (ISO/IEC 9899:2024)
- 6.7 宣告 (頁數:待補)
- C17 標準 (ISO/IEC 9899:2018)
- 6.7 宣告 (頁數:78-105)
- C11 標準 (ISO/IEC 9899:2011)
- 6.7 宣告 (頁數:108-145)
- C99 標準 (ISO/IEC 9899:1999)
- 6.7 宣告 (頁數:97-130)
- C89/C90 標準 (ISO/IEC 9899:1990)
- 3.5 宣告
[編輯] 參見 (See also)
| C++ 文件 關於 宣告 (Declarations)
|