C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
声明
声明是一个引入一个或多个标识符到程序中,并指定其含义及属性的 C 语言构造。
声明可以出现在任何作用域中。每个声明以分号结束(类似语句),并由两个独立部分组成:
specifiers-and-qualifiers declarators-and-initializers ;
|
|||||||||
其中
specifiers-and-qualifiers | - | 任意顺序的下列内容的空白符分隔列表
|
declarators-and-initializers | - | declarators 的逗号分隔列表(每个声明器提供附加类型信息及/或要声明的标识符)。 声明器可伴随初始化器。 enum 、 struct 和 union 声明可忽略 declarators ,这种情况下它们仅引入枚举常量和/或标签。
|
例如:
int a, *b=NULL; // “ int ”是类型指定符, // “ a ”是声明器 // “ *b ”是声明器而 NULL 是初始化器 const int *f(void); // “ int ”是类型指定符 // “ const ”是类型限定符 // “ *f(void) ”是声明器 enum COLOR {RED, GREEN, BLUE} c; // “ enum COLOR {RED, GREEN, BLUE} ”是类型指定符 // “ c ”是声明器
一个声明引入的每个标识符类型是通过 type specifier 所指定的类型及其 declarator 所应用的类型修饰决定的。
声明器
每个声明器是下列之一:
identifier | (1) | ||||||||
( declarator )
|
(2) | ||||||||
* qualifiers(可选) declarator
|
(3) | ||||||||
noptr-declarator [ static(可选) qualifiers(可选) expression ]
noptr-declarator |
(4) | ||||||||
noptr-declarator ( parameters-or-identifiers )
|
(5) | ||||||||
此语法背后的原因,是当声明器所声明的标识符以与声明器相同的形式出现在表达式中时,它会拥有类型指定符序列所指定的类型。
struct C { int member; // “ int ”是类型指定符 // “ member ”是声明器 } obj, *pObj = &obj; // “ struct C { int member; } ”是类型指定符 // 声明器“ obj ”定义 struct C 类型的对象 // 声明器“ *pObj ”声明指向 struct C 的指针, // 初始化器“ = &obj ”提供该指针的初值 int a = 1, *p = NULL, f(void), (*pf)(double); // 类型指定符是“ int ” // 声明器“ a ”定义一个 int 类型对象 // 初始化器“=1”提供其初值 // 声明器“ *p ”定义一个指向 int 指针类型的对象 // 初始化器“ =NULL ”提供其初值 // 声明器“ f(void) ”声明接受 void 并返回 int 的函数 // 声明器“ (*pf)(double) ”定义一个指向 // 接受 double 并返回 int 的函数的指针类型对象 int (*(*foo)(double))[3] = NULL; // 类型指定符是“int” // 1. 声明器“ (*(*foo)(double))[3] ”是数组声明器: // 所声明类型是“ 3 个 int 的数组的 /嵌套声明器/ ” // 2. 嵌套声明器是“ *(*foo)(double)) ”,是指针声明器 // 所声明类型是“ /嵌套声明器/ 指向 3 个 int 的数组的指针” // 3. 嵌套声明器是“ (*foo)(double) ”,是一个函数声明器 // 所声明类型是“ /嵌套声明器/ 接受 double 并返回指向 3 个 int 的数组的指针的函数” // 4. 嵌套声明器是“ (*foo) ”,是一个(有括号,函数声明器所要求)指针声明器。 // 所声明类型是“ /嵌套声明器/ 指向接受 double 并返回指向 3 个 int 的数组的指针的函数的指针” // 5. 嵌套声明器是“ foo ”,是一个标识符。 // 该声明引入一个标识符“ foo ”,以指代一个对象,其类型为 // “指向接受 double 并返回指向 3 个 int 的数组的指针的函数的指针” // 初始化器“ = NULL ”提供此指针的初值。 // 若在用于声明符形式的表达式使用“foo”,则表达式类型将是int。 int x = (*(*foo)(1.2))[0];
每个不属于其他声明器一部分的声明器结尾是一个顺序点。
定义
定义是一个提供所有关于其所声明标识符信息的声明。
对于函数,包含函数体的声明即是函数定义:
int foo(double); // 声明 int foo(double x){ return x; } // 定义
对于对象,分配其存储的声明(自动或静态,但、非 extern )即是定义,而一个不分配存储的声明(外部声明)不是。
extern int n; // 声明 int n = 10; // 定义
struct X; // 声明 struct X { int n; }; // 定义
重声明
若另一个同一标识符的声明在同一作用域的较早部分出现,则声明不可再引入同一标识符,除非
- 有链接对象(外部或内部)的声明可以重复:
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;
这些规则会简化头文件的使用。
注意
C89 中,任何复合语句(块作用域)中的声明必须出现在块的开头,在任何语句之前。 而且,C89 中返回 int 的函数可以隐式地用函数调用运算符声明,且使用旧式函数定义时, int 类型的函数参数不必声明。 |
(C99 前) |
禁止空声明器;声明必须是一个 _Static_assert 声明或 (C11 起)拥有至少一个声明器,或声明至少一个 struct/union/enum 标签,或引入至少一个枚举常量。
若声明器的任一部分是 VLA 数组声明器,则整个声明器的类型被称作“可变修改类型”。根据可变修改类型定义的类型同样是可变修改的( VM )。 任何可变修改类型声明只允许出现在块作用域或函数原型作用域,而且不能是任何结构体或联合体的成员。尽管 VLA 只能拥有自动存储期,一个 VM 类型,例如指向 VLA 的指针也可以有静态存储。关于 VM 类型有其他使用限制,见 goto 、 switch 、 longjmp 。 |
(C99 起) |
_Static_assert 从 C 文法的视角来看,被认为是声明(故它们可以出现在任何声明能出现的地方),但它们不会引入任何新的标识符,且不遵循声明语法。 |
(C11 起) |
引用
- C11 standard (ISO/IEC 9899:2011):
- 6.7 Declarations (p: 108-145)
- C99 standard (ISO/IEC 9899:1999):
- 6.7 Declarations (p: 97-130)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.5 Declarations