(x+1)>x如何评估为0和1?
我正在学习未定义的行为,并在没有任何明确解释的情况下偶然发现了这段代码:
#include <stdio.h>
#include <limits.h>
int foo ( int x) {
printf ("% dn" , x ); //2147483647
printf ("% dn" , x+1 ); //-2147483648 overflow
return ( x+1 ) > x ; // 1 but How????
}
int main ( void ) {
printf ("% dn" , INT_MAX ); //2147483647
printf ("% dn" , INT_MAX+1 ); //-2147483648 overflow
printf ("% dn" , ( INT_MAX+1 ) > INT_MAX ); //0 makes sense, since -ve < +ve
printf ("% dn" , foo(INT_MAX) ); //1
return 0;
}
在 gcc 上编译时,编译器发出警告:
警告:“int”类型的表达式中的整数溢出导致“-2147483648”
因此,显然 的值为INT_MAX+1负,这就解释了为什么(INT_MAX+1) > INT_MAX计算结果为 0。
但是,为什么(或如何)对in(x+1) > x求值为1?x = INT_MAXfoo(...)
回答
当程序表现出未定义的行为时,C 标准不会预测程序将做什么。程序可能会崩溃,可能会输出奇怪的结果,或者可能看起来工作正常。
事实上,编译器通常会在假设程序不包含未定义行为的情况下工作。
在这个表达式的情况下:
( x+1 ) > x
( x+1 ) > x
鉴于它x具有 type int,编译器知道有符号溢出是 UB 并且在它不会发生的假设下工作。考虑到这一点,x该表达式可能为假的地方没有值,因此编译器可以优化该表达式并将其替换为值 1。
当我在 gcc 4.8.5 下运行这个程序时,我得到以下结果-O0和-O1:
并以下列-O2和-O3:
2147483647
-2147483648
0
2147483647
-2147483648
0
然后foo在后一种情况下查看程序集:
foo:
.LFB11:
.file 1 "x1.c"
.loc 1 4 0
.cfi_startproc
.LVL0:
pushq %rbx // first call to printf
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
.loc 1 5 0
movl %edi, %esi
.loc 1 4 0
movl %edi, %ebx
.loc 1 5 0
xorl %eax, %eax
movl $.LC0, %edi
.LVL1:
call printf
.LVL2:
.loc 1 6 0 // second call to printf
leal 1(%rbx), %esi
movl $.LC0, %edi
xorl %eax, %eax
call printf
.LVL3:
.loc 1 8 0 // return value
movl $1, %eax
popq %rbx
.cfi_def_cfa_offset 8
.LVL4:
ret
.cfi_endproc
我们可以看到这正是编译器所做的:它优化了比较并始终返回 1。
这说明了编译器如何利用未定义的行为来应用各种优化。
- @avm The overhead of noticing undefined behaviour would be a massive loss. By design, C++ assumes you know what you're doing.
- @avm • **undefined behavior** is not a compiler problem, it's a programmer problem. C and C++ are not nanny languages. They presume the programmer knows what they are doing, and never lie to the compiler, and never have *undefined behavior* in their code. In the real world, this translates into an abundance of <strike>bugs</strike> *job security*.
- @avm: Other languages can and do do that. It slows down the code to always be checking for overflow. C does not do extra work that you didn't ask for.
- @avm It doesn't detect UB. It just assumes it won't happen. That's part of what makes C fast. It's up to the programmer to not introduce UB. And `INT_MAX+1 > INT_MAX` *is* UB. The fact that you get the result you expect doesn't change that.