作者:平凡天使007 | 来源:互联网 | 2023-05-16 08:04
规则2.1强制汇编语言应该被封装并隔离。在需要使用汇编指令的地方建议以如下方式封装并隔离这些指令(a)汇编函数(b)C函数(c)宏出于效率的考虑有时必须要嵌入一些简单的汇编指令如
规则2.1 强制 汇编语言应该被封装并隔离。
在需要使用汇编指令的地方建议以如下方式封装并隔离这些指令
(a) 汇编函数(b) C 函数(c) 宏
出于效率的考虑有时必须要嵌入一些简单的汇编指令如开关中断
如果不管出于什么原因需要这样做那么最好使用宏来完成
#define NOP asm (“ NOP”);
规则2.2 强制 源代码应该使用 /*…*/ 类型的注释 。
规则2.4 建议 代码段不应被注释掉(comment out)。
当源代码段不需要被编译时,应该使用条件编译来完成(如带有
注释的#if或#ifdef结构)。为这种目的使用注释的开始和结束标记
是危险的,因为C不支持嵌套的注释,而且已经存在于代码段中的任
何注释将影响执行的结果 。
规则5.1 强制 标识符(内部的和外部的)的有效字符不能多于31。
规则6.1 强制 单纯的char类型应该只用做存储和使用字符值 。
规则6.2 强制 signed char和unsigned char类型应该只用做存储
和使用数字值 。
有三种不同的char类型:单纯的char,unsigned char,signed
char。unsigned char和signed char用于数字型数据;char用于字符
型数据。单纯char类型的符号是实现定义的,不应依赖 。
单纯char类型所能接受的操作只有赋值和等于操作符(=、
==、!= )。
规则6.3 建议 应该使用指示了大小和符号的typedef以代替基本
数据类型 。
不应使用基本数值类型char、int、short、long、float和doulbe。
而应使用特定长度(specific-length)的typedef规则。6.3帮助我
们认清存储类型的大小,却不能保证可移植性,这是因为整数提升
(integral promotion的)不对称性。关于整数提升的讨论见节6.10
仍然很重要的是要理解整数大小的实现 。
程序员应该注意这些定义之下的typedef的实际实现 。
比如本文档中建议为所有基本数值类型和字符类型使用如下所示
的ISOPOSIX的typedef。对于32位计算机它们是:
typedef char char_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
typedef float float32_t;
typedef double float64_t;
typedef long double float128_t;
在位域类型的说明中typedef是不必要的。
规则6.4 强制 位域只能被定义为unsigned int或singed int类型。
规则6.5 强制 int类型的位域至少应该为2 bits长度。
1 bit长度的有符号位域是无用的 。
规则7.1 强制 不应使用八进制常量(零除外)和八进制escape序
列 。
规则8.5 强制 头文件中不应有对象或函数的定义。
头文件应该用于声明对象、函数、typedef和宏,而不应该包含或
生成占据存储空间的对象或函数(或它们的片断的定义)。这样就清
晰地划分了只有C文件才包含可执行的源代码,而头文件只能包含声
明 。
规则8.8 强制 外部对象或函数应该声明在唯一的文件中。
规则8.10 强制 在文件范围内声明和定义的所有对象或函数应该具
有内部链接,除非是在需要外部链接的情况下。
如果一个变量只是被同一文件中的函数所使用,那么就用static。
类似地,如果一个函数只是在同一文件中的其他地方调用,那么就用
static。使用static存储类标识符将确保标识符只是在声明它的文件
中是可见的,并且避免了和其他文件或库中的相同标识符发生混淆的
可能性 。
规则9.1 强制 所有自动变量在使用前都应被赋值 。
规则10.5 强制 如果位运算符 ~ 和 <<应用在基本类型为
unsigned char或unsigned short的操作数,结果应
该立即强制转换为操作数的基本类型 。
当这些操作符~和<<用在small integer类型(unsigned char或
unsigned short)时,运算之前要先进行整数提升,结果可能包含并
非预期的高端数据位,例如:
uint8_t port = 0x5aU;
uint8_t result_8;
uint16_t result_16;
uint16_t mode;
result_8 = (~port) >> 4; /* not compliant */
~ port 的值在16 位机器上是0xffa5 , 而在32 位机器上是
0xffffffa5。在每种情况下,result的值是0xfa,然而期望值可能是
0x0a。这样的危险可以通过如下所示的强制转换来避免:
result_8 = ( ( uint8_t ) (~port ) ) >> 4; /* compliant */
result_16 = ( ( uint16_t ) (~(uint16_t) port ) ) >> 4 ; /* compliant */
当<<操作符用在small integer类型时会遇到类似的问题,高端数
据位被保留下来。例如:
result_16 = ( ( port <<4 ) & mode ) >> 6 ; /* not compliant */
result_16的值将依赖于int实现的大小。附加的强制转换可以避
免任何模糊性 。
result_16 = ( ( uint16_t ) ( ( uint16_t ) port <<4 ) & mode ) >> 6 ; /* compliant
*/
规则10.6 强制 后缀“U”应该用在所有unsigned类型的常量上 。
规则12.7 强制 位运算符不能用于基本类型(underlying type)是
有符号的操作数上。
位运算(~、<<、>>、&、^ 和 |) 对有符号整数通常是无意义
的。比如:如果右移运算把符号位移动到数据位上或者左移运算把数
据位移动到符号位上,就会产生问题 。
规则12.9 强制 一元减运算符不能用在基本类型无符号的表达式
上。
规则12.10强制 不要使用逗号运算符。
规则13.5 强制 for语句的三个表达式应该只关注循环控制 。
for语句的三个表达式都给出时它们应该只用于如下目的 :
第一个表达式初始化循环计数器 (例子中的i );
第二个表达式应该包含对循环计数器(i)和其他可选的循环
控制变量的测试 ;
第三个表达式循环计数器(i)的递增或递减 。
规则14.5 强制 不应使用continue语句。
规则16.2 强制 函数不能调用自身不管是直接还是间接的。
规则16.7 建议 函数原型中的指针参数如果不是用于修改所指向的
对象就应该声明为指向const的指针。
本规则会产生更精确的函数接口定义const限定应当用在所指向
的对象而非指针因为要保护的是对象本身。例如:
void myfunc ( int16_t *param1, const int16_t *param2, int16_t *param3 )
/* param1 : Addresses an object which is modified – no const
param2 : Addresses an object which is not modified – const required
param3 : Addresses an object which is not modified – const missing */
{
*param1 = *param2 + *param3;
return;
}
/* data at address param3 has not been changed, but this is not const therefore
not compliant */
规则19.10 强制 在定义函数宏时每个参数实例都应该以小括号括起
来除非它们做为#或##的操作数。
函数宏的定义中参数应该用小括号括起来。例如一个abs函数可以
定义成 :
#define abs (x) ( ( (x) >= 0 ) ? (x) : -(x) )
不能定义成 :
#define abs (x) ( ( (x) >= 0 ) ? x : -x )
如果不坚持本规则,那么当预处理器替代宏进入代码时操作符优
先顺序将不会给出要求的结果。
考虑前面第二个不正确的定义被替代时会发生什么 。
z = abs ( a – b );
将给出如下结果:
z = ( ( a – b >= 0 ) ? a – b : -a – b );
子表达式 – a - b 相当于 (-a)-b而不是希望的 –(a-b)把所有
参数都括进小括号中就可以避免这样的问题 。
规则19.15 强制 应该采取防范措施以避免一个头文件的内容被包含
两次。
规则20.3 强制 传递给库函数的值必须检查其有效性。
规则20.4 强制 不能使用动态堆的内存分配 。
这排除了对函数alloc、malloc、realloc和free的使用。
规则20.5 强制 不要使用错误指示errno 。
规则20.7 强制 不应使用setjmp宏和longjmp函数。
规则20.8 强制 不应使用信号处理工具 。
规则20.9 强制 在产品代码中不应使用输入/输出库。
规则20.10强制 不应使用库中的函数atof、atoi和atol。
当字符串不能被转换时,这些函数具有未定义的行为。
规则20.12强制 不应使用库中的时间处理函数。
规则21.1 强制 最大限度降低运行时错误必须要确保至少使用了下
列方法之一:
a) 静态分析工具/技术;
b) 动态分析工具/技术 ;
c) 显式的代码检测以处理运行时故障 。