C编程
关键字表
ANSI(美国国家标准协会)C(C89)/ISO C(C90)
非常旧的编译器可能无法识别一些或所有C89关键字,如 const、enum、signed、void、volatile,以及任何后续标准中的关键字。
| 关键字 |
|---|
| auto |
| break |
| case |
| char |
| const |
| continue |
| default |
| do |
| double |
| else |
| enum |
| extern |
| float |
| for |
| goto |
| if |
| int |
| long |
| register |
| return |
| short |
| signed |
| sizeof |
| static |
| struct |
| switch |
| typedef |
| union |
| unsigned |
| void |
| volatile |
| while |
ISO C(C99)
这些关键字在大多数新编译器中得到支持。
| 关键字 |
|---|
| _Bool |
| _Complex |
| _Imaginary |
| inline |
| restrict |
ISO C(C11)
这些关键字仅在一些较新的编译器中得到支持。
| 关键字 |
|---|
| alignof |
| _Alignas |
| _Atomic |
| _Generic |
| _Noreturn |
| _Static_assert |
| _Thread_local |
虽然不严格来说是关键字,但C99兼容的预处理器/编译器还识别特殊的预处理器操作符 _Pragma,它作为 #pragma 指令的另一种形式,可以在宏展开时使用。例如,以下代码会导致一些编译器(如 GCC、Clang)发出诊断信息:
#define EMIT_MESSAGE(str) EMIT_PRAGMA(message(str))
#define EMIT_PRAGMA(content) _Pragma(#content)
EMIT_MESSAGE("Hello, world!")
一些编译器使用稍微不同的语法;特别是,MSVC支持 __pragma 代替 _Pragma。
特定编译器可能还会在非标准兼容模式下,或者通过额外的语法标记(如 __extension__)将一些其他词汇视为关键字,包括 asm、cdecl、far、fortran、huge、interrupt、near、pascal 或 typeof。然而,它们通常允许在标准兼容模式下通过声明来覆盖这些关键字(例如,通过定义一个名为 typeof 的变量),以避免与现有程序不兼容。为了确保编译器能够维护对扩展功能的访问,这些编译器通常会有一组以两个下划线(__)开头的适当关键字。例如,GCC将 asm、__asm 和 __asm__ 视为相似,但后两个始终保证具有预期的含义,因为它们无法被覆盖。
许多新引入的关键字——特别是那些以下划线和大写字母开头的,如 _Noreturn 或 _Imaginary——通常是间接使用的。开发人员应优先使用标准头文件,如 <stdbool.h> 或 <stdalign.h>,这些文件通常使用预处理器来建立该关键字的小写变体(例如,complex 或 noreturn)。这些头文件的目的是使 C 和 C++ 代码以及针对不同编译器或语言版本的代码能够更清洁地互操作。例如,通过包含 <stdbool.h>,在C99或C++中可以无差别地使用 bool、true 和 false,而不需要在C99中显式使用 _Bool 或在C++中使用 bool。
另见保留标识符列表 。
运算符表
此表中同一行的运算符具有相同的优先级,评估顺序由结合性(从左到右或从右到左)决定。表格中越接近顶部的运算符优先级越高,优先级较低的运算符位于后续的组别中。
| 运算符类型 | 描述 | 示例用法 | 结合性 |
|---|---|---|---|
| 后缀运算符 | 左到右 | ||
() |
函数调用运算符 | swap(x, y) |
左到右 |
[] |
数组下标运算符 | arr[i] |
左到右 |
. |
成员访问运算符,适用于结构体/联合体类型的对象或其引用 | obj.member |
左到右 |
-> |
成员访问运算符,适用于指向结构体/联合体对象的指针 | ptr->member |
左到右 |
| 一元运算符 | 右到左 | | ! | 逻辑非运算符 | !eof_reached | 右到左 | | ~ | 按位非运算符 | ~mask | 右到左 | | + - | 一元正负号运算符 | -num | 右到左 | | ++ -- | 后置自增/自减运算符 | num++ | 右到左 | | ++ -- | 前置自增/自减运算符 | ++num | 右到左 | | & | 地址运算符 | &data | 右到左 | | * | 间接运算符 | *ptr | 右到左 | | sizeof | 表达式的大小运算符 | sizeof 123 | 右到左 | | sizeof() | 类型的大小运算符 | sizeof(int) | 右到左 | | (type) | 类型转换运算符 | (float)i | 右到左 |
| 乘法运算符 | 左到右 | | * / % | 乘法、除法和取模运算符 | celsius_diff * 9.0 / 5.0 | 左到右 |
| 加法运算符 | 左到右 | | + - | 加法和减法运算符 | end - start + 1 | 左到右 |
| 位移运算符 | 左到右 | | << | 左移运算符 | bits << shift_len | 左到右 | | >> | 右移运算符 | bits >> shift_len | 左到右 |
| 关系不等运算符 | 左到右 | | < > <= >= | 小于、大于、小于或等于、大于或等于运算符 | i < num_elements | 左到右 |
| 关系等于运算符 | 左到右 | | == != | 等于、不等于运算符 | choice != 'n' | 左到右 |
| 按位与运算符 | 左到右 | | & | 按位与运算符 | bits & clear_mask_complement | 左到右 |
| 按位异或运算符 | 左到右 | | ^ | 按位异或运算符 | bits ^ invert_mask | 左到右 |
| 按位或运算符 | 左到右 | | | | 按位或运算符 | bits | set_mask | 左到右 |
| 逻辑与运算符 | 左到右 | | && | 逻辑与运算符 | arr != 0 && arr->len != 0 | 左到右 |
| 逻辑或运算符 | 左到右 | | || | 逻辑或运算符 | arr == 0 || arr->len == 0 | 左到右 |
| 条件运算符 | 右到左 | | ?: | 条件运算符 | size != 0 ? size : 0 | 右到左 |
| 赋值运算符 | 右到左 | | = | 赋值运算符 | i = 0 | 右到左 | | += -= *= /= | 复合赋值运算符 | num /= 10 | 右到左 | | %= &= |= ^= <<= >>= | 按位与、按位或、按位异或、按位移赋值运算符 | num /= 10 | 右到左 |
| 逗号运算符 | 左到右 | | , | 逗号运算符 | i = 0, j = i + 1, k = 0 | 左到右 |
数据类型表
| 类型 | 位数 | 备注 | 替代名称 |
|---|---|---|---|
| ANSI C (C89)/ISO C (C90) 中的基本类型 | |||
char |
≥ 8 | sizeof 返回以字符为单位的大小。这些“C字节”不必是8位字节(尽管通常是);字节数由 limits.h 头文件中的 CHAR_BIT 宏给出。符号性由实现定义。可以使用任何编码的8位或更少(例如 ASCII)来存储字符。整数运算仅对 0 ~ 127 范围内的值可移植。所有位都对 char 的值有贡献,即没有“空洞”或“填充”位。 |
— |
signed char |
与 char 相同 |
字符存储方式与 char 类型相同。可以可移植地存储范围为 -127 ~ 127 的整数。 |
— |
unsigned char |
与 char 相同 |
字符存储方式与 char 类型相同。可以可移植地存储范围为 0 ~ 255 的整数。 |
— |
short |
≥ 16,≥ char 的大小 |
可以可移植地存储范围为 -32767 ~ 32767 的整数。用于减少内存使用(尽管与 int 比较,生成的可执行文件可能更大且可能更慢)。 |
short int, signed short, signed short int |
unsigned short |
与 short 相同 |
可以可移植地存储范围为 0 ~ 65535 的整数。用于减少内存使用(尽管与 int 比较,生成的可执行文件可能更大且可能更慢)。 |
unsigned short int |
int |
≥ 16,≥ short 的大小 |
表示处理器处理的数据的“正常”大小(字长);这是通常使用的整数数据类型。可以可移植地存储范围为 -32767 ~ 32767 的整数。 | signed, signed int |
unsigned int |
与 int 相同 |
可以可移植地存储范围为 0 ~ 65535 的整数。 | unsigned |
long |
≥ 32,≥ int 的大小 |
可以可移植地存储范围为 -2147483647 ~ 2147483647 的整数。 | long int, signed long, signed long int |
unsigned long |
与 long 相同 |
可以可移植地存储范围为 0 ~ 4294967295 的整数。 | unsigned long int |
float |
≥ char 的大小 |
当使用的值变化不大时,用于减少内存使用。浮点格式由实现定义,不一定是 IEEE 单精度格式。unsigned 不能指定。 |
— |
double |
≥ float 的大小 |
表示处理器处理的数据的“正常”大小;这是通常使用的浮点数据类型。浮点格式由实现定义,不一定是 IEEE 双精度格式。unsigned 不能指定。 |
— |
long double |
≥ double 的大小 |
unsigned 不能指定。 |
— |
| ISO C (C99) 中新增的基本类型 | | | | | long long | ≥ 64,≥ long 的大小 | 可以可移植地存储范围为 -9223372036854775807 ~ 9223372036854775807 的整数。 | long long int, signed long long, signed long long int | | unsigned long long | 与 long long 相同 | 可以可移植地存储范围为 0 ~ 18446744073709551615 的整数。 | unsigned long long int | | intmax_t | 平台支持的最大宽度 | 可以存储范围为 -(1 << n-1) + 1 ~ (1 << n-1) - 1 的整数,其中 n 为 intmax_t 的宽度。用于 C 编程中的“j”长度修饰符,特别是在格式化输出函数(如 printf)中。 | — | | uintmax_t | 与 intmax_t 相同 | 可以存储范围为 0 ~ (1 << n) - 1 的整数,其中 n 为 uintmax_t 的宽度。 | — |
| 用户定义类型 | | | | | struct | ≥ 各成员的大小之和 | 称为聚合类型。 | — | | union | ≥ 最大成员的大小 | 称为聚合类型。 | — | | enum | ≥ char 的大小 | 枚举是与整数不同的类型,尽管它们是可以互相转换的。 | — | | typedef | 与被赋予名称的类型相同 | typedef 的语法与存储类如 static, register 或 extern 相似。 | — |
| 派生类型 | | | | | type* (指针) | ≥ char 的大小 | 0 始终表示空指针(无法存放数据的地址),无论空指针的位序列如何表示。指向不同类型的指针可能具有不同的表示方式,这意味着它们的大小也可能不同。因此,指针类型不可相互转换。即使在保证所有数据指针大小相同的实现中,函数指针和数据指针通常也不兼容。对于传递可变参数的函数,传递的参数必须是适当类型,因此即使是 0 也必须在这样的函数调用中强制转换为适当的类型。 | — | | type [integer[8]] (数组) | ≥ 整数 × type 的大小 | 方括号([])在声明中跟随标识符名称。在包含数组初始化的声明中(包括函数参数声明),数组的大小(整数)可以省略。type [] 不同于 type*,只有在某些情况下,二者才可以相互转换。 | — | | type (逗号分隔的类型/声明列表) (函数) | — | 声明没有任何存储类的函数为 extern。圆括号(())跟随标识符名称,例如:一个 2 参数的函数指针:int (* fptr)(int arg1, int arg2)。 | — |
字符集
用 C 语言编写的程序可以读取和写入任何字符集,前提是包含或使用了支持这些字符集的库。
然而,C 程序的源代码通常仅限于 ASCII 字符集。
在包含源代码的文件中,行的结束有时根据创建文件的操作系统不同,可能不是换行符,但编译器会将每行的结束处理为单个换行符。
几乎所有的编译器都允许 $、@ 和 ` 字符在字符串常量中使用。许多编译器还允许使用字面上的多字节 Unicode 字符,但它们并不具备可移植性。
某些字符必须使用反斜杠转义,以便在字符串或字符常量中表示它们自己。这些字符包括:
\\:字面反斜杠\":字面双引号\':字面单引号\n:换行符\t:水平制表符\f:换页符\v:垂直制表符
此外,某些编译器还允许以下字符:
\r:回车符\a:警报(可听的铃声)\b:退格符\xhh,其中'h'为十六进制数字,用于表示任意字节(包括\x00,零字节)。
\uhhhh 或 \Uhhhhhhhh,其中 'h' 为十六进制数字,用于可移植地表示 Unicode 字符。
参考
- IBM文档:保留标识符列表
- 非常老旧的编译器可能无法识别一元加号(+)操作符。
- -128 可以存储在二进制补码机器中(即大多数现有机器)。非常老旧的编译器可能无法识别
signed关键字。 - -32768 可以存储在二进制补码机器中(即大多数现有机器)。非常老旧的编译器可能无法识别
signed关键字。 - -2147483648 可以存储在二进制补码机器中(即大多数现有机器)。非常老旧的编译器可能无法识别
signed关键字。 - -9223372036854775808 可以存储在二进制补码机器中(即大多数现有机器)。
声明中的优先级:
[]、()(左结合性)— 最高*(右结合性)— 最低