不幸的是,你不能假設別的程序員總是能夠避免這種你認為“相當白癡”的事情。例如,最近有人報告我,他們遇到了一個包含goto的宏。我也見過這種情況,而且聽到過一些——在很脆弱的時候——看起來確實有理的意見。例如:
#define prefix get_ready(); int ret__
#define Return(i) ret__=i; do_something(); goto exit
#define suffix exit: cleanup(); return ret__
void f()
{
prefix;
// ...
Return(10);
// ...
Return(x++);
//...
suffix;
}
作為一個維護的程序員,就會產生這種印象;將宏“隱藏”到一個頭文件中——這并不罕見——使得這種“魔法”更難以被辨別。
一個常見的微妙問題是,一個函數風格的宏并不遵守函數參數傳遞的規則。例如:
#define square(x) (x*x)
void f(double d, int i)
{
square(d); // 好
square(i++); // 糟糕:這表示 (i++*i++)
square(d+1); //糟糕:這表示(d+1*d+1); 也就是 (d+d+1)
// ...
}
“d+1”的問題,可以通過在“調用”時或宏定義時添加一對圓括號來解決:
#define square(x) ((x)*(x)) /*這樣更好 */
但是, i++被執行了兩次(可能并不是有意要這么做)的問題仍然存在。
是的,我確實知道有些特殊的宏并不會導致C/C++預處理宏這樣的問題。但是,我無心去發展C++中的宏。作為替代,我推薦使用C++語言中合適的工具,例如內聯函數,模板,構造函數(用來初始化),析構函數(用來清除),異常(用來退出上下文環境),等等。
延伸閱讀
文章來源于領測軟件測試網 http://www.kjueaiud.com/