说明:为了方便对照标准的内容,标题从6.1开始
目录
6.1环境
1.1、强制:所有代码都必须遵照 ISO 9899:1990 “Programming languages - C”,由 ISO/IEC 9899/COR1:1995,ISO/IEC 9899/AMD1:1995,和 ISO/IEC9899/COR2:1996 修订
1.2、强制:不能有对未定义行为或未指定行为的依赖性。
1.3、强制:多个编译器和/或语言只能在为语言/编译器/汇编器所适合的目标代码 定义了通用接口标准时使用。
1.4、强制:编译器/链接器要确保 31 个有效字符和大小写敏感能被外部标识符支 持。
1.5、建议:浮点应用应该是英语已定义的浮点标准
6.2语言扩展
2.1(强制): 汇编语言应该被封装并隔离。
2.2(强制): 源代码应该使用 /*…*/ 类型的注释。
2.3(强制): 字符序列 /* 不应出现在注释中
2.4(建议): 代码段不应被“注释掉”(comment out)
6.3 文档
3.1(强制): 所有实现定义(implementation-defined)的行为的使用都应该文档化
3.2(强制): 字符集和相应的编码应该文档化
3.3(建议): 应该确定、文档化和重视所选编译器中整数除法的实现
3.4(强制): 所有#pragma 指令的使用应该文档化并给出良好解释
3.5(强制): 如果做为其他特性的支撑,实现定义(implementation-defined)的行为和位域(bitfields)集合应当文档化。
3.6(强制): 产品代码中使用的所有库都要适应本文档给出的要求,并且要经过适当的验证。
6.4 字符集
4.1(强制): 只能使用 ISO C 标准中定义的 escape 序列
4.2(强制): 不能使用三字母词(trigraphs)
6.5 标识符
5.1(强制): 标识符(内部的和外部的)的有效字符不能多于 31。
5.2(强制): 具有内部作用域的标识符不应使用与具有外部作用域的标识符相同的名称,这会隐藏了外部标识符
5.3(强制): typedef 的名字应当是唯一的标识符。
5.4(强制): 标签(tag)名称必须是唯一的标识符
5.5(建议): 具有静态存储期的对象或函数标识符不能重用
5.6(建议): 一个命名空间中不应存在与另外一个命名空间中的标识符拼写相同的标识符,除了结构和联合中的成员名字。
5.7(建议): 不能重用标识符名字。
6.6 类型
6.1(强制): 单纯的 char 类型应该只用做存储和使用字符值
6.2(强制): signed char 和 unsigned char 类型应该只用做存储和使用数字值
6.3(建议): 应该使用指示了大小和符号的 typedef 以代替基本数据类型。
6.4(强制): 位域只能被定义为 unsigned int 或 singed int 类型
6.5(强制): unsigned int 类型的位域至少应该为 2 bits 长度。
6.7 常量
7.1(强制): 不应使用八进制常量(零除外)和八进制 escape 序列
6.8 声明与定义
8.1(强制): 函数应当具有原型声明,且原型在函数的定义和调用范围内都是可见 的。
8.2(强制): 不论何时声明或定义了一个对象或函数,它的类型都应显式声明。
8.3(强制): 函数的每个参数类型在声明和定义中必须是等同的,函数的返回类型也该是等同的。
8.4(强制): 如果对象或函数被声明了多次,那么它们的类型应该是兼容的
8.5(强制): 头文件中不应有对象或函数的定义。
8.6(强制): 函数应该声明为具有文件作用域。
8.7(强制): 如果对象的访问只是在单一的函数中,那么对象应该在块范围内声明
8.8(强制): 外部对象或函数应该声明在唯一的文件中。
8.9(强制): 具有外部链接的标识符应该具有准确的外部定义
8.10(强制): 在文件范围内声明和定义的所有对象或函数应该具有内部链接,除非是在需要外部链接的情况下
8.11(强制): static 存储类标识符应该用于具有内部链接的对象和函数的定义和声明。
8.12(强制): 当一个数组声明为具有外部链接,它的大小应该显式声明或者通过初始化进行隐式定义。
6.9 初始化
9.1(强制): 所有自动变量在使用前都应被赋值。
9.2(强制): 应该使用大括号以指示和匹配数组和结构的非零初始化构造。
9.3(强制): 在枚举列表中,“=”不能显式用于除首元素之外的元素上,除非所有的元素都是显式初始化的。
6.10 数值类型转换
10.1(强制): 下列条件成立时,整型表达式的值不应隐式转换为不同的基本类型:
a) 转换不是带符号的向更宽整数类型的转换,或者
b) 表达式是复杂表达式,或者
c) 表达式不是常量而是函数参数,或者
d) 表达式不是常量而是返回的表达式。
10.2(强制): 下列条件成立时,浮点类型表达式的值不应隐式转换为不同的类型:
a) 转换不是向更宽浮点类型的转换,或者
b) 表达式是复杂表达式,或者
c) 表达式是函数参数,或者
d) 表达式是返回表达式。
10.3(强制): 整型复杂表达式的值只能强制转换到更窄的类型且与表达式的基本类型具有相同的符号
10.4(强制): 浮点类型复杂表达式的值只能强制转换到更窄的浮点类型。
10.5(强制): 如果位运算符 ~ 和 应用在基本类型为 unsigned char 或 unsigned short 的操作数,结果应该立即强制转换为操作数的基本类型。
10.6(强制): 后缀“U”应该用在所有 unsigned 类型的常量上。
6.11 指针类型转换
11.1(强制): 转换不能发生在函数指针和其他除了整型之外的任何类型指针之间。
11.2(强制): 对象指针和其他除整型之外的任何类型指针之间、对象指针和其他类型对象的指针之间、对象指针和 void 指针之间不能进行转换。
11.3(建议): 不应在指针类型和整型之间进行强制转换
11.4(建议): 不应在某类型对象指针和其他不同类型对象指针之间进行强制转换。
11.5(强制): 如果指针所指向的类型带有 const 或 volatile 限定符,那么移除限定符的强制转换是不允许的。
6.12 表达式
12.1(建议): 不要过分依赖 C 表达式中的运算符优先规则
12.2(强制): 表达式的值在标准所允许的任何运算次序下都应该是相同的。
12.3(强制): 不能在具有副作用的表达式中使用 sizeof 运算符
12.4(强制): 逻辑运算符 && 或 | | 的右手操作数不能包含副作用
12.5(强制): 逻辑 && 或 | | 的操作数应该是 primary-expressions。
12.6(建议): 逻辑运算符(&&、| | 和 !)的操作数应该是有效的布尔数。有效布尔类型的表达式不能用做非逻辑运算符(&&、| | 和 !)的操作数
12.7(强制): 位运算符不能用于基本类型(underlying type)是有符号的操作数上
12.8(强制): 移位运算符的右手操作数应该位于零和某数之间,这个数要小于左手操作数的基本类型的位宽。
12.9(强制): 一元减运算符不能用在基本类型无符号的表达式上。
12.10(强制): 不要使用逗号运算符。
12.11(建议): 无符号整型常量表达式的计算不应产生折叠
12.12(强制): 不应使用浮点数的基本(underlying)的位表示法(bit representation)
12.13(建议): 在一个表达式中,自增(++)和自减(- -)运算符不应同其他运算符混合在一起。
6.13 控制语句表达式
13.1(强制): 赋值运算符不能使用在产生布尔值的表达式上。
13.2(建议): 数的非零检测应该明确给出,除非操作数是有效的布尔类型。
13.3(强制): 浮点表达式不能做相等或不等的检测。
13.4(强制): for 语句的控制表达式不能包含任何浮点类型的对象
13.5(强制): for 语句的三个表达式应该只关注循环控制
13.6(强制): for 循环中用于迭代计数的数值变量不应在循环体中修改
13.7(强制): 不允许进行结果不会改变的布尔运算。
6.14 控制流
14.1(强制): 不能有不可到达(unreachable)的代码。
14.2(强制): 所有非空语句(non-null statement)应该:
a) 不管怎样执行都至少有一个副作用(side-effect),或者
b) 可以引起控制流的转移
14.3(强制): 在预处理之前,空语句只能出现在一行上;其后可以跟有注释,假设紧跟空语句的第一个字符是空格。
14.4(强制): 不应使用 goto 语句。
14.5(强制): 不应使用 continue 语句。
14.6(强制): 对任何迭代语句至多只应有一条 break 语句用于循环的结束。
14.7(强制): 一个函数在其结尾应该有单一的退出点
14.8(强制): 组成 switch、while、do...while 或 for 结构体的语句应该是复合语句
14.9(强制): if(表达式)结构应该跟随有复合语句。else 关键字应该跟随有复合语句或者另外的 if 语句
14.10(强制): 所有的 if ... else if 结构应该由 else 子句结束
6.15 switch 语句
15.1(强制): switch 标签只能用在当最紧密封闭(closely-enclosing)的复合语句是switch 语句体的时候
15.2(强制): 无条件的 break 语句应该终止每个非空的 switch 子句。
15.3(强制): switch 语句的最后子句应该是 default 子句
15.4(强制): switch 表达式不应是有效的布尔值。
15.5(强制): 每个 switch 语句至少应有一个 case 子句
6.16 函数
16.1(强制): 函数定义不得带有可变数量的参数
16.2(强制): 函数不能调用自身,不管是直接还是间接的。
16.3(强制): 在函数的原型声明中应该为所有参数给出标识符
16.4(强制): 函数的声明和定义中使用的标识符应该一致
16.5(强制): 不带参数的函数应当声明为具有 void 类型的参数
16.6(强制): 传递给一个函数的参数应该与声明的参数匹配。
16.7(建议): 函数原型中的指针参数如果不是用于修改所指向的对象,就应该声明为指向 const 的指针。
16.8(强制): 带有 non-void 返回类型的函数其所有退出路径都应具有显式的带表达式的 return 语句
16.9(强制): 函数标识符的使用只能或者加前缀&,或者使用括起来的参数列表,列表可以为空。
16.10(强制): 如果函数返回了错误信息,那么错误信息应该进行测试。
6.17 指针和数组
17.1(强制): 指针的数学运算只能用在指向数组或数组元素的指针上
17.2(强制): 指针减法只能用在指向同一数组中元素的指针上。
17.3(强制): >、>=、、不应用在指针类型上,除非指针指向同一数组
17.4(强制): 数组的索引应当是指针数学运算的唯一可允许的方式
17.5(建议): 对象声明所包含的间接指针不得多于 2 级
17.6(强制): 自动存储对象的地址不应赋值给其他的在第一个对象已经停止存在后仍然保持的对象。
6.18 结构与联合
18.1(强制): 所有结构与联合的类型应该在转换单元(translation unit)的结尾是完 善的。
18.2(强制): 对象不能赋值给重叠(overlapping)对象
18.3(强制): 不能为了不相关的目的重用一块内存区域。
18.4(强制): 不要使用联合。
6.19 预处理指令
19.1(建议): 文件中的#include 语句之前只能是其他预处理指令或注释。
19.2(建议): #include 指令中的头文件名字里不能出现非标准字符。
19.3(强制): #include 预处理指令应该跟随或”filename”序列
19.4(强制): C 的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、类型限定符、存储类标识符或 do-while-zero 结构。
19.5(强制): 宏不能在块中进行 #define 和 #undef
19.6(强制): 不要使用#undef
19.7(建议): 函数的使用优先选择函数宏(function-like macro)。
19.8(强制): 函数宏的调用不能缺少参数
19.9(强制): 传递给函数宏的参数不能包含看似预处理指令的标记
19.10(强制): 在定义函数宏时,每个参数实例都应该以小括号括起来,除非它们做为#或##的操作数。
19.11(强制): 预处理指令中所有宏标识符在使用前都应先定义,除了#ifdef 和#ifndef指令及 defined()操作符。
19.12(强制): 在单一的宏定义中最多可以出现一次 # 或 ## 预处理器操作符。
19.13(建议): 不要使用# 或 ## 预处理器操作符。
19.14(强制): defined 预处理操作符只能使用两种标准形式之一。
19.15(强制): 应该采取防范措施以避免一个头文件的内容被包含两次。
19.16(强制): 预处理指令在句法上应该是有意义的,即使是在被预处理器排除的情况下。
19.17(强制): 所有的 #else、#elif 和 #endif 预处理指令应该同与它们相关的 #if或#ifdef 指令放在相同的文件中。
6.20 标准库
20.1(强制): 标准库中保留的标识符、宏和函数不能被定义、重定义或取消定义。
20.2(强制): 不能重用标准库中宏、对象和函数的名字。
20.3(强制): 传递给库函数的值必须检查其有效性
20.4(强制): 不能使用动态堆的内存分配
20.5(强制): 不要使用错误指示 errno
20.6(强制): 不应使用库中的宏 offsetof
20.7(强制): 不应使用 setjmp 宏和 longjmp 函数
20.8(强制): 不应使用信号处理工具
20.9(强制): 在产品代码中不应使用输入/输出库。
20.10(强制): 不应使用库中的函数 atof、atoi 和 atol。
20.11(强制): 不应使用库中的函数 abort、exit、getenv 和 system。
20.12(强制): 不应使用库中的时间处理函数。
6.21 运行时错误
21.1(强制): 最大限度降低运行时错误必须要确保至少使用了下列方法之一:
a) 静态分析工具/技术;
b) 动态分析工具/技术;
c) 显式的代码检测以处理运行时故障