C中的多表达式宏

时间:2014-08-26 21:46:09

标签: c macros

#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 ; 
         };

我怀疑花括号末端的分号是导致问题的原因。但我不确定。谁能解释一下?

3 个答案:

答案 0 :(得分:5)

如果你想要一个扩展为语句的宏,那么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),它就不起作用。它只适用于整数。

答案 1 :(得分: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交换没有区别。

答案 2 :(得分:1)

是的,此时分号不合法。 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;