【问题标题】:multi-expression macro's in CC中的多表达式宏
【发布时间】:2014-08-26 21:46:08
【问题描述】:
#define SWAP(a,b) { a^=b ; b^=a ; a^=b; }

if (x < 0)
         SWAP(x,y);
else
         SWAP(y,x);    

我上面给出的代码不起作用。编译时出现以下错误。

trial.c:3:1: error: expected identifier or '(' before 'if'
trial.c:5:1: error: expected identifier or '(' before 'else'

我正在尝试找出它无法正常工作的确切原因。预处理器扩展宏如下

if (x < 0)
         { 
           x^=y ; 
           y^=x ; 
           x^=y ; 
         }; 
else
         { 
           y^=x ; 
           x^=y ; 
           y^=x ; 
         };

我怀疑花括号末尾的分号会导致问题。但我不确定。有人可以解释吗?

【问题讨论】:

  • 你的 ifelse 语句的结尾 } 后面的 ; 不应该在那里
  • 我知道该怎么做 :) 我想解释一下为什么上述方法不起作用。
  • 查看 if..else.. 的语法。
  • 您希望SWAP(x,y)SWAP(y,x) 做不同的事情吗?
  • C multi-line macro: do/while(0) vs scope block 的可能重复项。 “现在,如果你的宏是按照第二种方法定义的(只是'{'和'}'),代码将不再编译,因为'if'的'true'分支现在由复合语句表示。并且当你放一个';'在这个复合语句之后,你完成了整个 'if' 语句,从而孤立了 'else' 分支(因此编译错误)。"

标签: c macros


【解决方案1】:

如果您想要一个扩展为 语句 的宏,那么 do/while(0) 技巧就是最佳选择。

但如果可能的话,将宏扩展为表达式会更灵活。如果你想在语句上下文中使用它,只需添加一个分号:

#define SWAP(a, b) ( (a)^=(b), (b)^=(a), (a)^=(b) )

原始宏的问题,或者更确切地说是您使用它的方式的问题,是添加的分号创建了一个额外的语句。 if-else 语句的语法是

if (表达式 ) 语句 else 语句

通过同时提供块{ ... } 和分号,您在ifelse 之间有两个 语句。

do/while(0) 技巧解决了分号问题。编写一个扩展为表达式的宏(这并不总是可能的)完全避免了它。

更多观察:

您似乎期望SWAP(x, y)SWAP(y, x) 做不同的事情。它们的行为应该相同。

xor hack 确实允许您在不使用临时变量的情况下交换变量,但 99% 的情况下,仅使用临时变量更有意义。使用临时变量的一个问题是您必须声明它,这意味着您必须知道类型;这并不总是可能的。 xor hack 的一个缺点是,如果两个操作数是同一个对象(例如,arr[i]arr[j],其中i ==j),它就不起作用。而且它只适用于整数。

【讨论】:

    【解决方案2】:

    我怀疑花括号末尾的分号导致了问题

    完全正确!如果您在带有花括号的块之后放置一个分号,那将是一个新的、空的、if 之后的语句。编译器会这样解析:

    if (x < 0) // The "if"
             { // The body of the "if"
               x^=y ; 
               y^=x ; 
               x^=y ; 
             }
    ;    // <<== An empty statement after the one-sided "if"
    else // <<== A "stray" else (syntax error)
    

    这是宏的常见陷阱:如果您想在宏中使用花括号,请使用do / while(0) 技巧(解释为here):

    #define SWAP(a,b) do { a^=b ; b^=a ; a^=b; } while (0)
    

    注意:我希望这是一个学习练习,因为将AB 交换和将BA 交换没有区别。

    【讨论】:

      【解决方案3】:

      是的,此时分号是不合法的。 if(condition) { ... }; 不是格式良好的 if 语句,它要么是 if(condition) { ... } 要么是 if(condition) statement;

      一个经典的技巧是将宏内容包装为do { contents } while(0)。在这种情况下,需要在宏调用之后直接使用分号,因此感觉就像一个函数。

      然后扩展为

      if (x < 0)
          do { a^=b ; b^=a ; a^=b; } while (0);
      

      这是if 表达式的有效形式:if(condition) statement;

      【讨论】:

      • 您能否详细说明一下分号在这一点上是不合法的?
      • 完成!希望这会有所帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      相关资源
      最近更新 更多