【问题标题】:Why this If statment executing even when the condition is false?为什么即使条件为假,这个 If 语句也会执行?
【发布时间】:2014-01-10 14:15:07
【问题描述】:
#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

【问题讨论】:

  • 发现 XOR 交换有点像发现您可以用膝盖驾驶汽车。尝试一次,忘记它,然后继续前进。

标签: c macros


【解决方案1】:

您的 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 调用之后使用分号。

【讨论】:

  • 此外,宏参数名称应括在括号中,它们出现在替换列表中。
  • 当您进行替换时,发生了什么;在主要的 SWAP 之后有哪些?你忽略了吗?
  • @EricPostpischil - 好点;总的来说,这是一种很好的风格。 user2799508 - 该分号仍在代码中,作为一个空语句。我已经在上面的示例代码中添加了它。
【解决方案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)

请注意,宏定义以分号结尾。

【讨论】:

  • 你忘了上面的 } 吗?
【解决方案3】:

#define 语句表现为由预处理器完成的文本宏替换。您的if 语句实际上已转换为此(在编译之前):

if(x < 0)
    x ^= y; x ^= y; x ^= y;;

请注意您没有任何花括号,并且 if 中有多个表达式。只有第一个没有被执行。

每个编译器都应该支持一个标志来只输出预处理的代码。如果是 gcc,您可以通过以下方式查看:gcc -E -P i.c,以防您有疑问。

【讨论】:

  • 在您替换文本时,您为什么忽略原来的分号 SWAP(在 main 中)?
  • 这很危险,不如用安迪托马斯的方法。
  • 如果我将 MACRO 放在 {} 中,我会收到编译错误;正在制造麻烦。那么为什么会这样;在你的替换中被忽略了?
  • @user2799508 你指的是什么替换?我的第二个代码删除了尾随 ;?它不是必需的,因为这会将您的代码变成这样:x ^= y; x ^= y; x ^= y;;
  • 但是在第一个代码块中你写了 x ^= y; x^=y; x ^= y;
【解决方案4】:

您的SWAP 宏扩展为三个语句:其中只有一个适用于if 语句。您可以通过在宏中放置大括号来解决这个问题,或者更好的是,使用虚拟的 loop 结构。

但请注意;如果您真的想要使用 XOR 交换,那么您需要检查对象的地址是否不相同。否则你会得到一个奇怪的归零效果。

把它们放在一起,你就明白了

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

解决了这两个问题。 do while 循环意味着SWAP 的用户必须以; 终止:这是构建宏时的好习惯。

【讨论】:

  • 谢谢@EricPostpischil:我已经修改了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-25
  • 2015-03-05
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
相关资源
最近更新 更多