例如,永远不要像这样定义一个宏:
#define DANGER 60 + 2
当我们执行这样的操作时,这可能是危险的:
int wrong_value = DANGER * 2; // Expecting 124
相反,定义这样,因为你不知道宏的用户如何使用它:
#define HARMLESS (60 + 2)
这个例子很简单,但这几乎解释了我的问题.在编写宏时,您会建议使用哪些指南或最佳实践吗?
谢谢你的时间!
在执行一个运行其参数并且表现得像表达式的宏时,这是惯用的:
#define DOIT(x) do { x } while(0)
该表格具有以下优点:
它需要一个终止分号
它适用于嵌套和大括号,例如if/else
你不仅应该在参数周围放置parens,你应该在返回的表达式周围放置parens.
#define MIN(a,b) a < b ? a : b // WRONG int i = MIN(1,2); // works int i = MIN(1,1+1); // breaks #define MIN(a,b) (a) < (b) ? (a) : (b) // STILL WRONG int i = MIN(1,2); // works int i = MIN(1,1+1); // now works int i = MIN(1,2) + 1; // breaks #define MIN(a,b) ((a) < (b) ? (a) : (b)) // GOOD int i = MIN(1,2); // works int i = MIN(1,1+1); // now works int i = MIN(1,2) + 1; // works
但是,MIN(3,i++)
仍然破碎......
最好的规则是只有在没有其他方法可行时才使用#defines! 我知道你在问C而不是C++,但仍记得他的想法.
用括号围绕整个宏观和围绕在扩展列表中提到的每个参数:
#define MAX(x, y) ((x) > (y) ? (x) : (y))
避免编写多次评估其参数的宏.当参数有副作用时,这些宏不会按预期运行:
MAX(a++, b);
a++
如果a
大于,则评估两次b
.
使用宏的大写名称来表明它是一个宏而不是一个函数,因此可以相应地考虑差异(另一个一般的好习惯是不传递对函数有副作用的参数).
不要使用宏来重命名这样的类型:
#define pint int *
因为当有人打字时,它不会按预期运行
pint a, b;
请改用typedef.
使用静态const值而不是宏来表示常量值,整数或其他值.编译器通常可以优化它们,并且它们仍然是语言类型系统中的一级公民.
static const int DANGER = 60 + 2;
在扩展中,在括号周围加上括号,这样如果它们传入一个表达式,你就会得到预期的行为.
#define LESS_THAN(X,Y) (((X) < (Y) ? (X) : (Y))
对MAX / MIN宏的响应,该宏来自Linux内核中的GCC黑客:
#define min(x, y) ({ \ typeof(x) _min1 = (x); \ typeof(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; })