宏容易出错,因为它们依赖于文本替换,并且不执行类型判断.例如,此宏:
#define square(a) a * a
与整数一起使用时效果良好:
square(5) --> 5 * 5 --> 25
但是当与表达式一起使用时,会发生非常奇怪的事情:
square(1 + 2) --> 1 + 2 * 1 + 2 --> 1 + 2 + 2 --> 5
square(x++) --> x++ * x++ --> increments x twice
在参数周围加上括号有助于解决这些问题,但并不能完全消除这些问题.
当宏包含多个语句时,控制流构造可能会出现问题:
#define swap(x, y) t = x; x = y; y = t;
if (x < y) swap(x, y); -->
if (x < y) t = x; x = y; y = t; --> if (x < y) { t = x; } x = y; y = t;
解决此问题的通常策略是将语句放入"do{.}While(0)"循环中.
如果有两个 struct 碰巧包含一个名称相同但语义不同的字段,那么同一个宏可能对这两个 struct 都起作用,结果很奇怪:
struct shirt
{
int numButtons;
};
struct webpage
{
int numButtons;
};
#define num_button_holes(shirt) ((shirt).numButtons * 4)
struct webpage page;
page.numButtons = 2;
num_button_holes(page) -> 8
最后,宏可能很难调试,产生奇怪的语法错误或运行时错误,您必须进行扩展才能理解(例如,使用gcc-e),因为调试器无法单步调试宏,如本例所示:
#define print(x, y) printf(x y) /* accidentally forgot comma */
print("foo %s", "bar") /* prints "foo %sbar" */
内联函数和常量有助于避免宏中的许多此类问题,但并不总是适用的.在故意使用宏来指定多态行为的情况下,无意的多态可能很难避免.C++具有许多特征,如模板,可以帮助在不使用宏的情况下以类型化的方式创建复杂的多态 struct ;详情请参见Stroustrup's The C++ Programming Language.