跳转到内容

C 编程/语言参考

来自维基教科书,开放世界中的开放书籍
前一页: 代码库 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

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>,这些头文件通常使用预处理器来建立关键字的全小写变体(例如,complexnoreturn)。这些头文件的作用是使 C 和 C++ 代码以及针对不同编译器或语言版本的代码能够更干净地互操作。例如,通过包含 <stdbool.h>booltruefalse 标记可以在 C99 或 C++ 中以相同的方式使用,而无需在 C99 中显式使用 _Bool 或在 C++ 中显式使用 bool

另请参阅保留标识符列表[1]

运算符表

[编辑 | 编辑源代码]

此表中同一行的运算符具有相同的优先级,而求值的顺序由结合性决定(从左到右从右到左)。表中越靠前的运算符优先级越高,表中越靠后的运算符优先级越低。

运算符 描述 示例用法 结合性
后缀运算符 从左到右
() 函数调用运算符 swap (x, y)
[] 数组索引运算符 arr [i]
. 成员访问运算符
对于结构体/联合类型
或对它的引用
obj.member
-> 成员访问运算符
对于指向结构体/联合类型
对象的指针
ptr->member

一元运算符 从右到左
! 逻辑非运算符 !eof_reached
~ 按位非运算符 ~mask
+ -[2] 一元加/减运算符 -num
++ -- 后置递增/递减运算符 num++
++ -- 前置递增/递减运算符 ++num
& 取地址运算符 &data
* 间接寻址运算符 *ptr
sizeof sizeof 运算符 用于表达式 sizeof 123
sizeof() sizeof 运算符 用于类型 sizeof (int)
(类型) 类型转换运算符 (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
+= -= *= /=
%= &= |= ^=
<<= >>=
简写赋值运算符
(foo op= bar 代表
foo = foo op bar)
num /= 10

逗号运算符 从左到右
, i = 0, j = i + 1, k = 0

数据类型表

[编辑 | 编辑源代码]
类型 大小(以位计) 注释 备用名称
ANSI C (C89)/ISO C (C90) 中的原始类型
char ≥ 8
  • sizeof 给出以 char 单位的大小。这些“C 字节”不一定是 8 位字节(尽管通常是);位数由 limits.h 头文件中的 CHAR_BIT 宏给出。
  • 符号性是实现定义的。
  • 8 位或更小的任何编码(例如 ASCII)都可以用于存储字符。
  • 整数运算只能针对 0 ~ 127 范围内的值以可移植方式执行。
  • 所有位都对 char 的值有贡献,即没有“空洞”或“填充”位。
signed char char 相同
  • 字符存储方式与 char 类型相同。
  • 可以以可移植方式存储 -127 ~ 127 范围内的整数[3]
unsigned char char 相同
  • 字符存储方式与 char 类型相同。
  • 可以以可移植方式存储 0 ~ 255 范围内的整数。
short ≥ 16, ≥ char 的大小
  • 可以以可移植方式存储 -32767 ~ 32767 范围内的整数[4]
  • 用于减少内存使用量(虽然与使用 int 相比,生成的执行文件可能更大,而且可能更慢)。
short int, signed short, signed short int
unsigned short short 相同
  • 可以以可移植方式存储 0 ~ 65535 范围内的整数。
  • 用于减少内存使用量(虽然与使用 int 相比,生成的执行文件可能更大,而且可能更慢)。
unsigned short int
int ≥ 16,≥ short 的大小
  • 代表处理器处理数据的“正常”大小(字长);这是通常使用的整数数据类型。
  • 可移植地存储 -32767 ~ 32767 范围内的整数[4]
signedsigned int
unsigned int int 相同
  • 可以以可移植方式存储 0 ~ 65535 范围内的整数。
unsigned
long ≥ 32,≥ int 的大小
  • 可移植地存储 -2147483647 ~ 2147483647 范围内的整数[5]
long intsigned longsigned 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 范围内的整数[6]
long long intsigned long longsigned long long int
unsigned long long long long 相同
  • 可移植地存储 0 ~ 18446744073709551615 范围内的整数。
unsigned long long int
intmax_t 平台支持的最大宽度
uintmax_t intmax_t 相同
  • 可以存储 0 ~ (1 << n)-1 范围内的整数,其中 'n' 是 uintmax_t 的宽度。

用户定义类型
struct ≥ 每个成员大小的总和
  • 被称为聚合类型
union ≥ 最大成员的大小
  • 被称为聚合类型
enum char 的大小
  • 枚举是与 int 不同的类型,尽管它们可以互相转换。
typedef 与正在命名的类型相同
  • typedef 的语法类似于存储类,如 staticregisterextern

派生类型[7]
类型*

(指针)
char 的大小
  • 0 始终表示空指针(一个不能放置任何数据的地址),无论什么位序列表示空指针的值。
  • 指向不同类型的指针可能具有不同的表示形式,这意味着它们的大小也可能不同。因此,它们不能互相转换。
  • 即使在保证所有数据指针大小相同的实现中,函数指针和数据指针通常也彼此不兼容。
  • 对于接受可变数量参数的函数,传递的参数必须是适当的类型,因此即使 0 也必须在这样的函数调用中转换为适当的类型。
类型 [整数[8]]

(数组)
整数 × 类型 的大小
  • 方括号 ([]) 位于声明中的标识符名称之后。
  • 在同时初始化数组的声明(包括函数参数声明)中,数组的大小(整数)可以省略。
  • 类型 []类型* 不同。只有在某些情况下才能将其中一个转换为另一个。
类型 (逗号分隔的类型/声明列表)

(函数)
  • 没有声明任何存储类的函数为 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 字符。

参考文献

[编辑 | 编辑源代码]
  1. http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/topic/com.ibm.vacpp7a.doc/language/ref/clrc02reserved_identifiers.htm 保留标识符列表
  2. 非常旧的编译器可能无法识别一元 + 运算符。
  3. -128 可以存储在二进制补码机器(即大多数现有的机器)中。非常旧的编译器可能无法识别 signed 关键字
  4. a b -32768 可以存储在二进制补码机器(即大多数现有的机器)中。非常旧的编译器可能无法识别 signed 关键字
  5. -2147483648 可以存储在二进制补码机器(即大多数现有的机器)中。非常旧的编译器可能无法识别 signed 关键字
  6. -9223372036854775808 可以存储在二进制补码机器(即大多数现有的机器)中
  7. 标准没有对整数的大小/类型有任何限制,它是由实现定义的。标准中唯一提到的内容是,实现可能有内存块最大大小的限制,因此整数的限制将为 size_of_max_block/sizeof(type)
  8. 标准没有对整数的大小/类型有任何限制,它是由实现定义的。标准中唯一提到的内容是,实现可能有内存块最大大小的限制,因此整数的限制将为 size_of_max_block/sizeof(type)
前一页: 代码库 C 编程 下一页: 编译器
华夏公益教科书