命名空間
變體
動作

宣告

出自 cppreference.com
< c‎ | 語言

宣告 (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) - 以空白分隔的清單,順序不拘,包含:
  • 類型指定符 (type specifiers)


宣告子與初始化式 (declarators-and-initializers) - 以逗號分隔的 宣告子 (declarators) 清單(每個宣告子提供額外的類型資訊及/或要宣告的識別項)。宣告子可搭配 初始化式 (initializers)。列舉 (enum)、結構 (struct) 與聯合 (union) 的宣告可以省略 宣告子,此時它們僅引入列舉常數及/或標記 (tags)。
attr-spec-seq - (C23)選用的 屬性 (attributes) 清單,應用於被宣告的實體;若單獨出現則構成屬性宣告。
1,2) 簡單宣告。引入一個或多個代表物件、函數、struct/union/enum 標記、typedef 或列舉常數的識別項。
3) 屬性宣告。不宣告任何識別項,若標準未定義其含義,則其含義由實作定義。

例如:

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) [ 限定符 (qualifiers) (選用) * ]

(4)
非指標宣告子 (noptr-declarator) ( 參數或識別項 (parameters-or-identifiers) ) (5)
1) 此宣告子引入的識別項。
2) 任何宣告子皆可置於括號內;這在引入陣列指標與函數指標時是必要的。
3) 指標宣告子:宣告 S * cvr D;將 D 宣告為指向由 S 所決定類型之 cvr-限定的指標。
4) 陣列宣告子:宣告 S D[N]D 宣告為包含 N 個由 S 所決定類型之物件的陣列。非指標宣告子 指除未加括號的指標宣告子以外的任何其他宣告子。
5) 函數宣告子:宣告 S D(params)D 宣告為接受 params 參數並回傳 S 的函數。非指標宣告子 指除未加括號的指標宣告子以外的任何其他宣告子。

此語法背後的邏輯是:當宣告子所宣告的識別項,以與該宣告子相同的形式出現在運算式中時,它將具有由類型指定符序列所指定的類型。

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) 是提供其所宣告識別項所有資訊的宣告。

每個 enumtypedef 的宣告都是定義。

對於函數,包含函數體的宣告即為 函數定義

int foo(double); // declaration
int foo(double x) { return x; } // definition

對於物件,配置儲存空間(自動或靜態,但不包含 extern)的宣告即為定義;而不配置儲存空間的宣告(外部宣告)則不是。

extern int n; // declaration
int n = 10; // definition

對於 structunion,指定成員清單的宣告即為定義。

struct X; // declaration
struct X { int n; }; // definition

[編輯] 重宣告 (Redeclaration)

若在相同 作用域 (scope) 中,已存在相同識別項的先前宣告,則宣告無法再次引入該識別項,除非:

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 類型的使用還有其他限制,請參閱 gotoswitchlongjmp

(自 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)
English Deutsch 日本語 한국어 中文(简体) 中文(繁體)