宏是预处理器将在真实代码中放入的复制/粘贴的文本;宏的作者希望替换将产生有效的代码。
要成功,有三个好的“技巧”:
帮助宏表现得像真正的代码
普通代码通常以分号结尾。用户是否应该查看不需要的代码...
doSomething(1) ;
DO_SOMETHING_ELSE(2) // <== Hey? What's this?
doSomethingElseAgain(3) ;
这意味着如果缺少分号,则用户希望编译器产生错误。
但是真正真正的好理由是,宏的作者有时可能需要用真正的功能替换宏(也许是内联的)。因此,宏实际上应该像一个宏。
因此,我们应该有一个需要分号的宏。
产生有效的代码
如jfm3的答案所示,有时该宏包含多个指令。而且,如果在if语句中使用了宏,则将出现问题:
if(bIsOk)
MY_MACRO(42) ;
该宏可以扩展为:
#define MY_MACRO(x) f(x) ; g(x)
if(bIsOk)
f(42) ; g(42) ; // was MY_MACRO(42) ;
g
无论的值如何,都将执行该函数bIsOk
。
这意味着我们必须将范围添加到宏:
#define MY_MACRO(x) { f(x) ; g(x) ; }
if(bIsOk)
{ f(42) ; g(42) ; } ; // was MY_MACRO(42) ;
产生有效的密码2
如果宏类似于:
#define MY_MACRO(x) int i = x + 1 ; f(i) ;
以下代码可能会出现另一个问题:
void doSomething()
{
int i = 25 ;
MY_MACRO(32) ;
}
因为它将扩展为:
void doSomething()
{
int i = 25 ;
int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}
当然,此代码不会编译。因此,该解决方案再次使用范围:
#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }
void doSomething()
{
int i = 25 ;
{ int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}
该代码再次正常运行。
结合分号+范围效应?
有一种C / C ++习惯用法可以产生这种效果:do / while循环:
do
{
// code
}
while(false) ;
do / while可以创建范围,从而封装宏的代码,最后需要用分号,从而扩展为需要一个代码的代码。
奖金?
C ++编译器将优化do / while循环,因为在编译时就知道其后置条件为false。这意味着一个宏像:
#define MY_MACRO(x) \
do \
{ \
const int i = x + 1 ; \
f(i) ; g(i) ; \
} \
while(false)
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
MY_MACRO(42) ;
// Etc.
}
将正确扩展为
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
do
{
const int i = 42 + 1 ; // was MY_MACRO(42) ;
f(i) ; g(i) ;
}
while(false) ;
// Etc.
}
然后被编译和优化为
void doSomething(bool bIsOk)
{
int i = 25 ;
if(bIsOk)
{
f(43) ; g(43) ;
}
// Etc.
}
void
在末尾添加一个类型的表达式...例如((void)0)。