功能类宏中的交换功能

时间:2015-08-24 15:42:46

标签: c

浏览以下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

为什么我错了?

6 个答案:

答案 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 )行附近添加花括号将解决您的问题。或者,您可以在宏声明中的三行代码周围放置花括号。