当前位置:首页 > > 大橙子疯嵌入式


前言

这篇重点介绍一下代码编程规范的扩展要求-宏/常量规范要求

要求

【规范1】用宏定义表达式时,要使用完备的括号

因为宏只是简单的代码替换,不会像函数一样先将参数计算后,再传递。

// 错误示例 #define RECTANGLE_AREA(a, b) a * b // RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 1 + 2 * 3 + 6, 因为符号优先级此时和想要的结果完全不同 #define RECTANGLE_AREA(a, b) (a * b) #define RECTANGLE_AREA(a, b) (a) * (b) // 10 / RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 10 / (1 + 2) * (3 + 6), 结果不同 // 正确示例 #define RECTANGLE_AREA(a, b) ((a) * (b)) // RECTANGLE_AREA(1 + 2, 3 + 6) 替换时为 ((1 + 2) * (3 + 6)), 结果一致 

【规范2】将宏所定义的多条表达式放在大括号中

若宏定义函数表达式,则记得加换行符 \,建议使用do{...}while(0)的方式

#define DOSOMETHING() \
do \
{ \
 fool1(); \
 fool2(); \
}while(0) 

【规范3】不允许直接使用魔鬼数字

使用魔鬼数字的弊端:代码难以理解;如果一个有含义的数字多处使用,一旦需要修改这个数值,代价惨重。

使用明确的物理状态或物理意义的名称能增加信息,并能提供单一的维护点。

解决途径:对于局部使用的唯一含义的魔鬼数字,可以在代码周围增加说明注释,也可以定义局部const变量,变量命名自注释。对于广泛使用的数字,必须定义const全局变量/宏;同样变量/宏命名应是自注释的。0作为一个特殊的数字,作为一般默认值使用没有歧义时,不用特别定义

【规范4】除非必要,应尽可能使用函数代替宏

宏对比函数,有一些明显的缺点:

  • 宏缺乏类型检查,不如函数调用检查严格;

  • 宏展开可能会产生意想不到的副作用,如#define SQUARE(a) (a) * (a)这样的定义,如果是SQUARE(i++),就会导致i被加两次;如果是函数调用double square(double a) {return a * a;}则不会有此副作用;

  • 以宏形式写的代码难以调试难以打断点,不利于定位问题;

  • 宏如果调用的很多,会造成代码空间的浪费,不如函数空间效率高。

【规范5】常量建议使用const定义代替宏

当编译报错时,只会显示常量,不会显示宏定义的名字,查找时很费劲(因为宏是替换,在编译过程中称为“预处理”)
一般情况下在意常量的类型,就使用const,如果是头文件对外提供的常量,使用宏定义

【规范6】宏定义中尽量不使用return、goto、continue、break等改变程序流程的语句

如果在宏定义中使用这些改变流程的语句,很容易引起资源泄漏问题,使用者很难自己察觉。
错误示例:在某头文件中定义宏CHECK_AND_RETURN:


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭