作业出错了。这是gcc的bug吗?

-1 c gcc integer-overflow

//filename:mt.c\n//filename is useful to understand the gcc command\n#include <stdio.h>\nint isTmax(int x);\n\nint main()\n{\n    printf("wtf %d\\n", isTmax(0x7fffffff));\n    return 1;\n}\n\nint isTmax(int x)\n{\n    int y = ((x + x + 2) ^ 1);\n    int z = (!(~(x + x + 2) + 1) ^ 0);\n    printf("y = %d\\n", y);\n    printf("z = %d\\n", z);\n    return y & z;\n} \n
Run Code Online (Sandbox Code Playgroud)\n

代码很奇怪,因为它是一个 csapp 讲义解决方案(显然是错误的)。(x+x+2)当 x 等于 0x7fffffff 时,\n 等于 0。(~(x+x+2)+1)由于溢出所以等于0。所以(!(~(x+x+2)+1)^0)等于1。调试时观察验证了这一点。\n我认为,正常情况下,赋值后z应该为1。

\n

环境\xef\xbc\x9a{系统\xef\xbc\x9awindows 10; 虚拟系统ubuntu 20.04 LTS;虚拟机软件:VirtualBox 6.1;GCC:gcc(Ubuntu 9.3.0-17ubuntu1~20.04)9.3.0}

\n

\n

这张图片有更多细节。VScode正在连接上述虚拟系统。

\n

\n

完全相同的代码在另一个环境中表现不同。另一种环境\xef\xbc\x9a{系统:windows 10; 虚拟系统:ubuntu 20.04 LTS;虚拟机软件:VirtualBox 6.1;GCC:gcc(Ubuntu 5.4.0-6ubuntu1~16.04.12)5.4.0 20160609}

\n

\n

Kev*_*vin 5

有符号整数溢出是未定义的行为,因此您的代码无效。如果我们看一个例子

int isTmax(int x)
{
    int z = (!(~(x + x + 2) + 1) ^ 0);
    return z;
}
Run Code Online (Sandbox Code Playgroud)

其汇编输出如下:

push    rbp
mov     rbp, rsp
mov     DWORD PTR [rbp-20], edi
cmp     DWORD PTR [rbp-20], -1
sete    al
movzx   eax, al
mov     DWORD PTR [rbp-4], eax
mov     eax, DWORD PTR [rbp-4]
pop     rbp
ret
Run Code Online (Sandbox Code Playgroud)

相关部分是cmp指令,它将DWORD PTR [rbp-20](即参数x)与 -1 进行比较。它不进行计算,而是x与 -1 进行比较。如果x是 -1,则计算结果为:

   !(~(-1 + -1 + 2) + 1)
-> !(~(-2 + 2) + 1)
-> !(~0 + 1)
-> !(-1 + 1)
-> !0
-> 1
Run Code Online (Sandbox Code Playgroud)

由于有符号整数溢出是未定义的行为,因此编译器不必考虑任何x会导致溢出的值。所以如果x不是-1,你最终会得到

   !(~(non-zero) + 1)
-> !((non-negative-one) + 1)
-> !(non-zero)
-> 0
Run Code Online (Sandbox Code Playgroud)

切换x为无符号后,编译器现在必须考虑溢出(因为它是允许的)。所以该函数编译为:

push    rbp
mov     rbp, rsp
mov     DWORD PTR [rbp-20], edi
mov     eax, DWORD PTR [rbp-20]
add     eax, 1
add     eax, eax
neg     eax
test    eax, eax
sete    al
movzx   eax, al
mov     DWORD PTR [rbp-4], eax
mov     eax, DWORD PTR [rbp-4]
pop     rbp
ret
Run Code Online (Sandbox Code Playgroud)

在这里,它会按照您的预期加载xeax进行计算。