C宏扩展如何工作?

时间:2012-02-26 06:01:17

标签: c macros

让我解释一下我对示例代码的困惑

这是我们的宏

#define rsAssert(v)   if(!(v)) printf("rsAssert failed: %s, in %s at %i" #v, __FILE__, __LINE__); 

案例1:

int main(void)
{
  rsAssert(0);
  return 0;
}

此案例成功编译

案例2

int main(void)
{
  rsAssert(0)  // note here ;  is not present
  return 0;
}

这也是无懈可击的 问题1:

这意味着您是在写rsAssert(0)还是rsAssert(0);之间没有区别?


然后

案例3

int main()
{
  if(1)
    rsAssert(0);
  else 
    printf("mr.32");
  return 0;
}

这里rsassert(0);不会编译[见http://ideone.com/7dFv1] 但没有; rsasser(0)正常[见http://ideone.com/8fehl] ..

我不知道宏观扩张在这里发生了什么......

4 个答案:

答案 0 :(得分:4)

它在案例3中不起作用的原因是因为这是实际编译的内容:

int main()
{
if(1)
  if(!(v)) printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__);;
else 
  printf("mr.32");
return 0;
}

请注意宏中第一个printf末尾的额外分号。

通常情况下,使用if语句,后跟单个语句或带有{}的块。

但由于额外的,你有这个:

if (...) 
    printf(...); ;
else
    printf(...);
return 0;

这个额外的分号是一个空洞的陈述,但仍然是一个陈述。

你应该删除;从宏观。然后事情会更有意义。

答案 1 :(得分:4)

这是我总是强制我的程序员在所有if语句中使用主体的最大原因。

int main()
{
  if (1)
    if(!(0))
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
    else 
      printf("mr.32");
  return 0;
}

受到良好编码标准的阻碍

int main()
{
  if (1){
    if(!(0)){
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
      }
    }
    else {
      printf("mr.32");
    }
  return 0;
}

修复了低成本的变化列表。

#define rsAssert(v) (printf( (!v)?"rsAssert failed: %s, in %s at %i":"", #v, __FILE__, __LINE__))

这将有效但总是会打印一个printf。

#define rsAssert(v) ((!v)?printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__):0)

这只会在你查询断言时打印出来,但看起来很麻烦

还要考虑以下几点!

if( rand()%2 )
  FooLog("Hello World");
ImportantFunction();

#if DEBUG
#define FooLog printf
#else
#define FooLog //
#endif

在发布时,重要功能在50%的时间内100%有效。

答案 2 :(得分:2)

我预计在案例3中根本不起作用。手工扩张(并使其有意义):

int main()
{
  if (1)
    if(!(0))
      printf("rsAssert failed: %s, in %s at %i", "0", __FILE__, __LINE__);
    else 
      printf("mr.32");
  return 0;
}

正如您所看到的,else最终会出现错误的if声明。如果您希望包含if语句的宏起作用,则需要使其看起来像一个简单的语句。将其包含在do... while(0)中是惯用的:

#define rsAssert(v)                                                         \
    do {                                                                    \
      if(!(v))                                                              \
        printf("rsAssert failed: %s, in %s at %i", #v, __FILE__, __LINE__); \
    } while (0) 

答案 3 :(得分:1)

if(1)
  rsAssert(0); // Original semicolon
else 
  ....

扩展为

if(1)
   if(!(v)) printf("rsAssert failed: %s, in %s at %i",
       #v, __FILE__, __LINE__);; // Notice the extra semicolon. The extra from the
                                 // macro expansion.
else
    ....

这个额外的分号会导致一个新的空语句。由于没有{},因此对于if语句,else不会立即被跟踪,而且编译器正在抱怨。所以,做 -

if(1)
{
  rsAssert(0);
}
 else 
  ....