#include<stdio.h>
int main()
{
// We use a trick involving exclusive-or to swap two variables
#define SWAP(a, b) a ^= b; b ^= a; a ^= b;
int x = 10;
int y = 5;
printf("%d%d\n",x,y );
if(x < 0)
SWAP(x, y);
printf("%d%d",x,y );
return 0;
}
输出结果为:
105
515
即使条件在if(10 <0为假)中评估为假,这个5 15即将来临?
答案 0 :(得分:9)
您的SWAP宏调用将被预处理器替换。虽然它出现在一行上,但只有第一个语句是if
语句的一部分。
if(x < 0)
SWAP(x, y);
由预处理器转换为:
if(x < 0)
a ^= b; b ^= a; a ^= b; ;
实际上与以下内容相同:
if(x < 0)
a ^= b;
b ^= a;
a ^= b;
;
您可以通过将宏定义中的所有语句放入块中来解决此问题,如下所示:
#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while( 0 )
do / while技巧允许您使用分号跟随SWAP调用。
答案 1 :(得分:2)
因为宏体不是声明:它是三个。
如果您将宏替换为其定义,if
读取如下:
if(x < 0)
x ^= y; x ^= y; x ^= y;
当然与以下内容相同:
if(x < 0)
x ^= y;
x ^= y;
x ^= y;
由于宏调用周围没有大括号,因此只有第一个分配“属于”if
。
修复是将宏包含在“虚拟”循环中:
#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while(0)
请注意,宏定义不以分号结尾。
答案 2 :(得分:1)
#define
语句表现为由预处理器完成的文本的宏替换。您的if
语句实际上已转换为此语句(在编译之前):
if(x < 0)
x ^= y; x ^= y; x ^= y;;
注意你没有任何花括号,if里面有多个表达式。只有第一个没有被执行。
每个编译器都应该支持一个标志来只输出预处理的代码。如果是gcc,你可以看到它:gcc -E -P i.c
如果你有疑问。
答案 3 :(得分:0)
您的SWAP
宏已扩展为三个语句:其中只有一个适用于if
语句。您可以通过在宏中添加大括号来修复它,或者更好的是,使用虚拟loop
结构。
但请注意;如果你真的想要使用XOR交换,那么你需要检查对象的地址是不一样的。否则你会得到好奇的归零效果。
总而言之,你得到了这个
#define SWAP(a, b) do { if (&a != &b){ a ^= b; b ^= a; a ^= b; } } while 0
解决了这两个问题。 do
while
循环意味着SWAP
的用户必须以;
终止:在构建宏时,这是一种很好的做法。