为何constexpr修饰的uint16_t变量按位取反时会被编译器转换为int
问题原因解析
基础规则:整型提升是核心前提
C++标准规定了**整型提升(integral promotion)**规则:所有取值范围小于int的整型类型,在参与算术运算前都会被隐式转换为int类型(前提是int可以容纳原类型的所有取值)。
在绝大多数主流平台上,int是32位有符号整数,完全可以覆盖uint16_t的取值范围(0~65535),所以不管变量有没有constexpr修饰,你对uint16_t类型的值执行~按位取反操作时,都会先发生两步处理:
- 原
uint16_t值0xFFFF先被提升为int类型,值为0x0000FFFF - 对提升后的
int值执行按位取反,得到结果0xFFFF0000,对应有符号int的取值就是-65536
这个结果传入要求uint16_t参数的函数f时,需要做类型转换,-65536转换为16位无符号整数会溢出,最终得到0,这就是警告描述的问题:
warning: unsigned conversion from 'int' to 'uint16_t' {aka 'short unsigned int'} changes value from '-65536' to '0' [-Woverflow]
为什么只有constexpr修饰时才出警告
constexpr的作用是标记变量为编译期常量,编译器会在编译阶段直接完成~DefaultValueForPortStatus的计算,明确知道这个转换过程会发生值溢出,所以直接触发警告。
去掉constexpr后,变量变为普通运行期变量,GCC默认不会对运行期的隐式类型转换做溢出检查,所以不会弹出警告。如果给GCC添加-Wconversion编译参数,无论是否加constexpr都会触发该警告。
修复方案
如果需要保留uint16_t按位取反的逻辑,只需要显式处理类型转换即可消除警告:
// 方案1:显式转换回uint16_t f(static_cast<uint16_t>(~DefaultValueForPortStatus)); // 方案2:位与清除高位 f(~DefaultValueForPortStatus & 0xFFFF);
内容的提问来源于stack exchange,提问作者bielu000
相关产品推荐
相关产品推荐

