MISRA-C:2004规则常⽤要点规则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)是银行卡csc
有符号的操作数上。
位运算(~、<<、>>、&、^ 和 |) 对有符号整数通常是⽆意义
的。⽐如:如果右移运算把符号位移动到数据位上或者左移运算把数
据位移动到符号位上,就会产⽣问题 。
规则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 : Address an object which is modified – no const
param2 : Address an object which is not modified – const required
param3 : Address 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 强制 不应使⽤tjmp宏和longjmp函数。
规则20.8 强制 不应使⽤信号处理⼯具<signal.h> 。
规则20.9 强制 在产品代码中不应使⽤输⼊/输出库<stdio.h>。
规则20.10强制 不应使⽤库<stdlib.h>中的函数atof、atoi和atol。当字符串不能被转换时,这些函数具有未定义的⾏为。
规则20.12强制 不应使⽤库<time.h>中的时间处理函数。
规则21.1 强制 最⼤限度降低运⾏时错误必须要确保⾄少使⽤了下列⽅法之⼀:
a) 静态分析⼯具/技术;
b) 动态分析⼯具/技术 ;
c) 显式的代码检测以处理运⾏时故障 。