C++常规算术转换:cpp.sh与godbolt结果不同,孰是孰非?
问题分析与结论
代码与现象
测试代码如下:
// Example program #include <iostream> using namespace std; int main() { unsigned long a = 0; int b = 1; long long c = -1; cout << (c < a*b) << endl; }
- godbolt编译运行返回
0 - cpp.sh编译运行返回
1
标准规则依据
C++常规算术转换的核心规则:
- 若无符号类型U的整数转换秩大于等于有符号类型S的秩,则转换类型为U
- 否则,若S能表示U的所有值,则转换类型为S
- 否则,转换为对应于S的无符号整数类型
问题分析
拆解表达式c < a*b的执行逻辑:
- 计算
a*b:a是unsigned long,b是int。由于unsigned long的秩高于int,b会被转换为unsigned long,计算结果为0UL,类型为unsigned long。 - 比较
c < 0UL:
在主流64位平台中,unsigned long和long long的秩相同(均为64位整数类型)。按照规则,此时应将long long类型的c(值为-1)转换为unsigned long类型,转换后的值为64位无符号整数的最大值(18446744073709551615)。
比较该最大值与0UL,结果为false,对应输出0——这符合标准,也是godbolt的正确结果。
不符合标准的编译器
cpp.sh使用的编译器不符合C++标准。原因是它错误地将unsigned long类型的0UL转换为long long类型的0,进而比较-1 < 0得到true并输出1,违反了“无符号类型与有符号类型秩相同时,将有符号类型转换为无符号类型”的规则。
内容的提问来源于stack exchange,提问作者toxic
相关产品推荐
相关产品推荐

