先生,请您告诉我为什么' C '中的以下条件是false
?
main()
{
int i=1;
if(i<=i++)
printf("false");
else
printf("true");
}
先生,请您告诉我为什么' C '中的以下条件是false
?
main()
{
int i=1;
if(i<=i++)
printf("false");
else
printf("true");
}
这不是假的,你只是false
在它是真的时打印。
比较运算符<=
没有指定首先评估哪一侧, thei
或/gnu-c-manual/gnu-c-manual.html#Sequence-Points)。i++
如果首先评估左侧,您将得到:
if (1 <= 1)
如果首先评估右侧,您会得到:
if (2 <= 1)
这突出了问题,但比这更糟糕。
您编写了具有未定义行为的代码,这意味着“未定义”。在这种情况下,编译器可以做任何事情并且仍然符合标准。
例如,这些编译器(带有-O3
)遵循 else 分支:
虽然这些编译器(带有-O3
)遵循true
分支:
g++-4.7 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 4.7.3
其他编译器可以做一些完全不同的事情。
这是未指定行为和简单明了的未定义行为的组合。所以你无法预测这段代码的结果,也不能依赖结果。未指定,因为在此行中:
if(i<=i++)
我们不知道是先评估i
还是i++
先评估。C99 标准部分草案第6.5
3 段说:
运算符和操作数的分组由语法指示。74) 除稍后指定(对于函数调用 ()、&&、||、?: 和逗号运算符)外,子表达式的求值顺序和中的顺序发生哪些副作用都未指定。
上面提到的行也是未定义的行为,因为在序列点之间我们只允许修改一次变量,如果我们修改它,我们只允许读取以前的值来确定要设置的新值。在这种情况下,我们正在读取先验值以确定i
和i++
。从标准部分草案6.5
第 2 段:
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。此外,应仅读取先验值以确定要存储的值。
要了解您的代码在做什么,我将重新编写,只会非常明确:
main()
{
int i=1;
if(i<=i) {
i++;
printf("false");
} else {
i++:
printf("true");
}
}
比较后i++
增加 i的方法。在 if i 的两个分支中,我都在递增,所以它是等价的。