代码编程规范-扩展(宏/常量)
扫描二维码
随时随地手机看文章
前言
这篇重点介绍一下代码编程规范的扩展要求-宏/常量规范要求
要求
【规范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:





