为什么 Clang 和 GCC 中两个无符号整数之和的结果类型不同
Why is the result type of a sum of two unsigned integers different in Clang and GCC
我正在为我的模拟器编写一些低级代码,其中涉及大量 16 位和 8 位无符号整数。我在项目中启用了-Wconversion
警告,所有警告都被视为错误(-Werror
(。
请考虑以下代码片段:
#include <cstdint>
int main ()
{
uint16_t a = 4;
uint16_t b = 6;
uint16_t c = a + b;
}
直到 GCC 9.3 将-std=c++17 -Wconversion -Werror
作为编译标志,才会给出以下错误:
<source>: In function 'int main()':
<source>:7:20: error: conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} may change value [-Werror=conversion]
7 | uint16_t c = a + b;
| ~~^~~
但是相同的代码不会为GCC 10.1
和任何编译器版本的Clang
给出此错误(测试到Clang 5.0.0
年(。链接到编译器资源管理器。
所以我的问题如下:
- IMO,添加两个
unsigned ints
不应隐式转换为int
。还是我的假设是错误的? - 为什么
Clang
和GCC
(直到 9.3(会产生不同的结果?标准是否规定了此操作的任何约束,还是由编译器供应商决定? GCC 10.1
有什么变化?为什么这个错误没有弹出GCC 10.1
?
IMO,添加两个无符号整数不应隐式转换为整数。还是我的假设是错误的?
这个假设没有错。无符号 int 永远不会隐式转换为 int。
但是,在您的系统上,uint16_t恰好是无符号的短int。假设无符号的短 int 没有隐式转换为 int 是一个错误的假设。在大多数系统上,它们被提升为 int。
最近有一个很好的问题,为什么促销是签署int:https://stackoverflow.com/a/62042330/2079303
为什么Clang和GCC(直到9.3(会产生不同的结果?
他们没有。两者都将晋升为 int。一个人根本没有警告转换。转换不是格式不正确的,因此不需要发出诊断。
还是由编译器供应商决定?
诊断消息由编译器供应商自行决定(除非另有指定,否则程序格式不正确时需要诊断消息(。
GCC 10.1 中有哪些变化?为什么GCC 10.1没有弹出此错误?
也许他们认为警告在这种情况下没有用,并摆脱了它。
代码中没有添加两个unsigned int
。实际上你添加了两个unsigned short
,因为uint16_t
是unsigned short
的typedef。
整数提升规则规定,任何比int
窄的整数类型(显示为+
的操作数(都会提升为int
(而不是预期的unsigned int
(。
因此,所涉及的步骤是将(int)4
添加到(int)6
给予(int)10
,然后将其分配回c
。
你应该发现所有的编译器都给出了正确的c
值,代码的行为是明确定义的。
-Wconversion
的行为更具争议性。 由于此代码是一个完美的示例,因此它通常会为定义良好的代码发出警告。 除了不使用标志或以某种方式包装误报(可能通过#pragma
或函数调用(之外,这个问题没有明显的解决方案。
有些人确实希望看到此代码的警告,而有些人则不希望。-Wconversion
生成警告的确切案例集在 gcc 中不断变化,因为人们提交错误报告,他们 {do|don't} 希望看到针对某些特定情况的警告。
我遇到了同样的警告,因为我做了一点转变:
uint8_t left_shift(uint8_t a, uint8_t b) { return a << b; }
启用-Wconversion
警告的 Clang 输出:
<source>:10:53: warning: implicit conversion loses integer precision: 'int' to 'uint8_t' (aka 'unsigned char') [-Wimplicit-int-conversion]
uint8_t left_shift(uint8_t a, uint8_t b) { return a << b; }
~~~~~~ ~~^~~~
但是程序集列表没有显示其他人在此线程中引用的幻影int
促销的迹象。 在整个过程中仅使用byte
宽度:
https://godbolt.org/z/eSVaQW
left_shift(unsigned char, unsigned char):
push rbp
mov rbp, rsp
mov byte ptr [rbp - 1], dil
mov byte ptr [rbp - 2], sil
movzx eax, byte ptr [rbp - 1]
movzx ecx, byte ptr [rbp - 2]
shl eax, cl
movzx eax, al
pop rbp
ret
- 为什么 Clang 和 GCC 中两个无符号整数之和的结果类型不同
- 迭代器和无符号整数的重载 + 运算符
- C++编译错误(有符号和无符号整数表达式之间的比较)
- C++无符号整数和无符号长整形整数之间的区别
- C++中的无符号整数
- C++ 有符号和无符号整数表达式之间的比较
- C / C++中无符号整数的减法和比较是否定义良好?
- 有符号和无符号整数表达式之间的比较
- 有符号整数和无符号整数C++的实现差异
- 消除有符号和无符号整数表达式之间比较的优雅方式
- 有符号整数和无符号整数之间的转换
- 将负整数强制转换为更大的无符号整数
- 如何在位集中存储随机生成的无符号整数
- 最小的无符号整数,可以包含给定有符号积分的正值
- 作为二进制压缩为无符号整数的无符号整数半字节
- C++中用于循环的无符号整数
- gcc(TDM-GCC)中的无符号整数溢出错误
- 使用连续的无符号整数列表初始化 std::vector<无符号 int>
- 基本级别的映射,"此常量表达式的类型为"const char*",而不是所需的"无符号整数"类型
- 如何将长整数和/或无符号整数传递给 MPI 参数