浏览以下C代码
# define swap(a,b) temp=a; a=b; b=temp;
main( )
{
int i, j, temp;
i=5;
j=10;
temp=0;
if( i > j)
swap ( i, j );
printf ( "%d %d %d", i, j, temp);
}
编译器输出:
10 0 0
我期待这个输出
10 5 0
为什么我错了?
答案 0 :(得分:5)
缺少牙箍。这是宏的常见缺陷之一。让我们看看会发生什么:
if(i > j)
swap(i, j);
变为:
if(i > j)
temp = a; a = b; b = temp;;
更具可读性:
if(i > j)
temp = a;
a = b;
b = temp;
所以行a = b;
和b = temp;
将始终执行,它们不属于if
正文。
在if
或宏周围放置大括号。
答案 1 :(得分:5)
使用do{
... }while(0)
来定义类似语句的宏要好得多(参见this):
#define swap(a,b) do { int temp=a; a=b; b=temp; } while(0)
因为正确理解了do{
.... }while(0)
构造(即使是条件等的然后或else
部分等。 ..正如其他答复中所解释的那样。
实际上,如果您使用swap
参数调用temp
(例如swap(temp,xx)
),或者如果您使用副作用的第二个参数(例如{{swap(x,y++)
),您仍会遇到问题1}}会增加y
两次,而不是按你想要的那样做。)
顽强的swap
可能会在预处理级别使用concatenation,并使用GCC特定__COUNTER__
predefined macro之类的独特计数器来生成唯一符号(而不是temp
})
答案 2 :(得分:2)
您的问题是此行中的if条件:
if( i > j)
swap ( i, j );
预处理器替换了您的定义后,这些行如下所示:
if( i > j)
temp=a; a=b; b=temp;
您的期望如下:
if( i > j)
{temp=a; a=b; b=temp;}
可以通过将您的定义更改为
来实现#define swap(a,b) {temp=a; a=b; b=temp;}
修改强> 正如其他人所提到的,更强大的解决方案是将宏定义为
#define swap(a,b) do{temp=a; a=b; b=temp;}while(1)
这仍然需要手动声明变量temp
。
可以在此处找到类型无关交换宏的一个很好的示例:https://stackoverflow.com/a/3982430/5237890
答案 3 :(得分:2)
您应该在宏声明中添加花括号来解决您的问题。
此外,如果您想交换基本类型,例如 int ,您可以使用 XOR 运算符来交换值使用另一个变量。
#define swap(a, b) { a ^= b; b ^= a; a ^= b; }
答案 4 :(得分:1)
另一个问题是行
if( i > j)
在您的情况下,i = 5且j = 10,因此swap()
行的第一个语句不会被执行。正如@Kninnug指出的那样(几乎)没有花括号,你的代码实际上是
if(i > j)
temp = i;
i = j
j = temp;
现在,由于I = 5且j = 10,因此只执行最后两行,因此我变为10(j的值),j变为零(temp的值)。
答案 5 :(得分:0)
当使用类似函数的宏时,编译器只需用宏声明中的文本替换调用函数的代码中的文本。在if语句之后你没有使用大括号,如果你只需要执行一行代码就可以了。但是当编译器为宏函数执行文本替换时,现在需要在if语句下嵌套三行代码。
在第Swap ( a, b )
行附近添加花括号将解决您的问题。或者,您可以在宏声明中的三行代码周围放置花括号。