WeHack BBS
未定义行为之有符号数转无符号数 - 可打印的版本

+- WeHack BBS (https://bbs.wehack.space)
+-- 版块: 计算机技术 (https://bbs.wehack.space/forum-5.html)
+--- 版块: 程序设计讨论区 (https://bbs.wehack.space/forum-14.html)
+--- 主题: 未定义行为之有符号数转无符号数 (/thread-202.html)



未定义行为之有符号数转无符号数 - vimacs - 11-25-2020

代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main()
{
    char str[20];
    scanf("%s", str);
    int32_t x = strtol(str, NULL, 0);

    uint32_t u = abs(x); // x=0x80000000 will trigger an undefined behavior
    uint64_t val = u;

    printf("0x%llx\n", val);
}

输入0x80000000. 在clang -O2,clang -O0,gcc -O0都输出0x80000000. 但是gcc -O2输出0xffffffff80000000.


RE: 未定义行为之有符号数转无符号数 - vimacs - 11-25-2020

最后查到问题了,是因为abs(INT_MIN)是未定义行为,在编译器优化了之后产生了奇怪的结果。


RE: 未定义行为之有符号数转无符号数 - nadebula - 12-03-2020

这个未定义行为不在于“有符号数转无符号数”,C的<stdlib.h>中定义的abs()函数的原型是int abs(int);,返回值仍为int而非unsigned。
发生未定义行为的原因在于abs(INT_MIN)的返回值不能由它的类型(int)表示。另外cppreference以及大多数C语言教材(受谭浩强误导)有误,假设int为32位,则INT_MIN应该是-2147483647-1,而不是-2147483648,因为后者不是int类型的表达式,它是由2147483648这个整数字面量加上一元负号构成的一元表达式,而2147483648不是int类型的整数字面量,它是long long类型。
参见键盘农夫著《狂人C》,国内非常难得的一本“不谭”的C语言教材。