MISRA C 一点总结
程序员文章站
2024-01-23 18:43:10
...
2.语言扩展
2.1 汇编语言应该通过a.汇编函数,b.C函数,c.宏三种方式封装并隔离汇编指令;
例如#define NOP asm(" NOP");
2.2 源代码应该使用/*...*/类型注释,而不是使用 这样C99类型和C++类型的注释,其作为对C90的扩展;
2.3 字符/* 不应该出现在注释中,因为C不支持注释的嵌套;
2.4 当源代码段不需要被编译时,应当使用条件编译完成例如#if、#elif、#else、#endif、#ifdef、#ifndef;
3 文档
3.1 所选编译器中整数除法的实现需要确定;
3.2 所有#pragma指令使用需要给出注释;
3.3 对位域的使用需要文档化,对结构体位域的使用可参考;
https://www.cnblogs.com/balingybj/p/4780358.html
4 字符集
4.1 只能使用ISO C标准中定义的转义字符串(escape sequence);
[http://m.php.cn/manual/view/34273.html](http://m.php.cn/manual/view/34273.html)
[https://en.wikipedia.org/wiki/Escape_sequences_in_C](https://en.wikipedia.org/wiki/Escape_sequences_in_C)
4.2 标识符
1、无论是内部标识符还是外部标识符的有效字符都不能多于31;
2、具有内部作用域的标识符不应当使用具有外部作用域的标识符相同的名称,这会隐藏外部标识符,PS:作用域主要看{};
3、typedef的名字应该是唯一标识符,不允许被重用;
4、不同tag标签必须是唯一的,不能够被重用,例如struct stag,union stag就不可以;
5、不管作用域如何,具有静态存储器的对象或者函数标识符不应被系统内所有源文件中重用;PS:这很容易理解
6、不考虑作用域,一个命名空间中不应该存在于另一个命名空间中标识符拼写相同的标识符,除了struct和union中成员名字,PS:意思enum也不可以。
5 类型
5.1 单纯的char类型只能用于存储和使用字符值;
5.2 signed char和unsigned char类型只能用于存储和使用数字值;
5.3 应当使用指示大小和符号的typedef 替代基本数据类型;
5.4 位域只能被定义为unsigned int或者signed int类型,同时unsigned int类型位域长度至少为2bits;
6 常量
6.1 不要使用八进制常量和八进制的转义字符串;
7 声明与定义
7.1 外部对象或者函数应该声明在唯一的文件中;
7.2 在文件范围内声明和定义的所有对象和函数应该具有内部连接,除非需要外部连接。例如如果一个变量或者函数只在一个文件中使用,就用static修饰;
8 初始化
8.1 自动变量在使用前应该被赋值;
8.2 在枚举列表中"="不能显式用于除首元素之外的元素上,除非所有元素都显式初始化;PS:很容易理解,怕出错。
9 数据类型转换
9.1 隐式和显式类型转换
1、对于数值丢失、符号丢失、精度丢失这些危险的类型换换需要强制使用显式类型转换来完成;
2、对于函数形、函数返回值、复杂表达式都必须使用显式类型转换;
9.2 整数后缀
1、所有unsigned类型的常量都必须后缀"U";
9.3 指针类型转换
1、void*指针可以被自动转化为特定指针类型;
2、函数指针不能够转换到除整型之外其他类型的指针;
3、某类型对象指针不能和其他不同类型对象指针之间进行强制转换;PS:不同结构体对象指针就不能相互转换;
4、如果指针指向的类型带有const或者voliate限定符,移除限定符的强制转换时不允许的;
10 表达式
1、不要过分依赖运算符优先级,但是也不要使用过多的括号;
2、表达式的值在标准允许的任何运算次序下都应该是相同的;
以下例子是不被允许的:
x = b[i]+i++; x = func(i++,i); p->task_start_fn(p++); x = f(a) + g(a);
3、位运算符不能用于基本类型是有符号类型的操作数上;
4、移位运算符的右手操作数应该小于左手操作数的基本类型的位宽;
5、一元减运算符不能用在无符号类型的表达式上;
11 控制流
1、不应该使用goto语句和continue语句;
2、一个函数在其结尾应该有单一的退出点,即一个函数最多有一个return语句;
3、所有if...else if结构应该以else子句结束;
4、无条件的break语句应该终止每个非空的switch子句,即每个switch子句中最后一条语句应该是break语句;
5、switch语句最后子句应该是default子句;
12 函数
1、函数定义不得带有可变数量的参数;
关于可变参参考:https://blog.csdn.net/php_boy/article/details/6654132
2、函数不能调用自身,不管是直接或者间接的,即不允许递归调用;
3、函数原型中的指针参数如果不是用于修改所指向的对象,就应该声明为指向const的指针;
4、如果函数返回错误信息,那么错误信息应该被测试;
13 指针和数组、联合
1、数组的索引应该是指针数学运算中唯一可允许的方式;
2、对象声明所包含的间接指针不得多于2级;
3、不要使用联合
14 预处理指令
1、C的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的表达式、类型限定符、存储类型标识符或者do-while(0)结构;
2、宏不能在块中进行#define和#undef;
3、不要使用#undef;
4、函数的使用优先选择函数宏,并且函数宏的调用不能缺少参数;
5、传递给函数宏的参数不能包含看似预处理指令的标记;
6、在定义函数宏时,每个参数实例都应该以小括号括起来,除非他们作为#和##的操作数;
#define abs(x) (((x)>0)?(x):(-x))
7、应该采取防范措施避免一个头文件的内容被包含两次;
8、所有的#else、#elif和#endif预处理指令应该同与他们相关的#if或者#ifdef指令放在相同的文件中;
15 标准库
1、标准库中保留的标识符、宏和函数不能被重新定义或者取消定义;
2、不能重用标准库中宏、对象和函数的名字;
3、由于C标准库中很多函数根据ISO标准,并不需要检查传递给她们的参数的有效性,所以传递给库函数的值必须检查其有效性;
4、不能使用动态堆得内存分配,即对函数alloc、malloc、realloc和free的使用;
5、不要使用错误提示errno;
6、不要使用库<stddef>中的宏offsetof;
7、不要使用setjmp宏和longjmp宏;
8、不要使用信号处理工具<signal.h>;
9、在产品代码中不要使用<stdio.h>;
10、不要使用库<stdlib.h>中的函数atof、atoi和atol;
11、不要使用库<stdlib.h>中的函数abort、exit、getenv和system;
12、不要使用库<time.h>中的时间处理函数;