我认为GCC错误地产生了[-Wshift-负值]警告。
我有一个函数,应该产生一个由单个输入参数提供的一定长度的后缀掩码:
#include <stdint.h>
uint16_t get_suffix_mask_sht(uint8_t shift) {
return (~(~((uint16_t) 0) << shift));
}
我尝试在不同版本的gcc上使用以下编译器选项来编译此函数
-Werror -Wextra
如果我将输出从uint16_t
更改为uint8_t
,也会发生此警告。较大的输出类型,即uint32_t
不会产生此警告。
我使用的是旧版GCC:7.4。但是我已经使用最新的GCC 9.x版本在godbolt上进行了尝试,它们都产生相同的警告。但是Clang版本不会产生此错误。
答案 0 :(得分:5)
当小于int
的变量(例如uint16_t
)与按位补数运算符~
一起使用时,它们就是promoted to int
。
类型int
是带符号的,在移位时不能很好地工作。尤其要考虑到~0
将是-1
,带有二进制补码(这是在二进制系统上表示负数的最常见表示法)。
一种可行的解决方案是使用较大的无符号类型(例如unsigned int
),然后在完成时使用屏蔽来获取较小类型的相关位。
答案 1 :(得分:3)
警告是正确的。
~((uint16_t) 0)
产生负值,因为在执行按位补码之前,(uint16_t) 0
的结果被提升为int
。
通常,使用移位时,您应该首选无符号整数(足够宽以避免类型提升)。我的建议是改用unsigned int
零:
return (~(~0U << shift));