关键字表

ANSI(美国国家标准协会)C(C89)/ISO C(C90)

非常旧的编译器可能无法识别一些或所有C89关键字,如 constenumsignedvoidvolatile,以及任何后续标准中的关键字。

关键字
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__)将一些其他词汇视为关键字,包括 asmcdeclfarfortranhugeinterruptnearpascaltypeof。然而,它们通常允许在标准兼容模式下通过声明来覆盖这些关键字(例如,通过定义一个名为 typeof 的变量),以避免与现有程序不兼容。为了确保编译器能够维护对扩展功能的访问,这些编译器通常会有一组以两个下划线(__)开头的适当关键字。例如,GCC将 asm__asm__asm__ 视为相似,但后两个始终保证具有预期的含义,因为它们无法被覆盖。

许多新引入的关键字——特别是那些以下划线和大写字母开头的,如 _Noreturn_Imaginary——通常是间接使用的。开发人员应优先使用标准头文件,如 <stdbool.h><stdalign.h>,这些文件通常使用预处理器来建立该关键字的小写变体(例如,complexnoreturn)。这些头文件的目的是使 C 和 C++ 代码以及针对不同编译器或语言版本的代码能够更清洁地互操作。例如,通过包含 <stdbool.h>,在C99或C++中可以无差别地使用 booltruefalse,而不需要在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 的整数,其中 nintmax_t 的宽度。用于 C 编程中的“j”长度修饰符,特别是在格式化输出函数(如 printf)中。 | — | | uintmax_t | 与 intmax_t 相同 | 可以存储范围为 0 ~ (1 << n) - 1 的整数,其中 nuintmax_t 的宽度。 | — |

| 用户定义类型 | | | | | struct | ≥ 各成员的大小之和 | 称为聚合类型。 | — | | union | ≥ 最大成员的大小 | 称为聚合类型。 | — | | enum | ≥ char 的大小 | 枚举是与整数不同的类型,尽管它们是可以互相转换的。 | — | | typedef | 与被赋予名称的类型相同 | typedef 的语法与存储类如 static, registerextern 相似。 | — |

| 派生类型 | | | | | 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 可以存储在二进制补码机器中(即大多数现有机器)。

声明中的优先级:

  • []()(左结合性)— 最高
  • *(右结合性)— 最低

标准中没有对整数的大小或类型进行任何限制,这取决于实现。标准中唯一提到的是,某些实现可能会对可以分配的最大内存块大小设定限制,因此整数的限制将为 size_of_max_block / sizeof(type)

Last modified: Sunday, 12 January 2025, 1:04 PM