为什么这段代码被解析为真?

时间:2012-01-07 16:18:17

标签: c

int main() {
    int a = 1;
    int b = 0;

    if (a = b || ++a == 2)
        printf("T: a=%i, b=%i", a, b);
    else
        printf("F: a=%i, b=%i", a, b);

    return 0;
}

让我们来看看这个简单的代码片段。结果是: T:a = 1,b = 0

为什么呢? (注意a=b使用赋值操作数,而不是比较)

我在这里理解的是,分配给 a ,然后 a 增加到1. 1不等于2所以结果确实应该是 a = 1,b = 0 。但为什么这个条件评估为真? (a=b)(++a == 2)都不是......我错过了什么?

这是另一个按预期打印 F 的短程序:

int main() {
    int a = 1;
    int b = 0;

    if (a = b) printf("T"); else printf("F");

    return 0;
}

3 个答案:

答案 0 :(得分:27)

你混淆了误导性的间距。

if (a = b || ++a == 2)

与:

相同
if (a = (b || ((++a) == 2)))

这实际上有未定义的行为。虽然b的评估与((++a) == 2)的评估之间存在一个序列点,但隐含的a分配与另一个a的分配之间没有序列点。由于明确的=分配。

答案 1 :(得分:2)

实际上,赋值具有最低的运算符优先级,因此if语句等效于:

if ( a = ( b || ( ++a == 2 ) ) )

所以你将a分配给1,但也在同一个表达式中递增它。我认为这会导致未定义的行为,但最终结果是编译器中的a为1。

答案 2 :(得分:0)

如果您正在使用具有类似有用警告的GCC或其他编译器,打开警告会给您一个非常大的提示,指出这里出了什么问题。使用gcc -Wall

  

警告:建议用作真值的分配括号

准确地说:编译器将代码解释为if (a = (b || ++a == 2)),并且警告建议您将其编写为if ((a = (b || ++a == 2)))以强调代码是预期的,而不是更多的错字共同if (a == (b || ++a == 2))

所以警告需要一些解释。为了获得所需的效果,巧合的是,您需要在用作真值的不同赋值周围添加括号,即(a = b)。尽管如此,警告告诉您,对于这一特定代码行有些不妥,值得进一步审查。