编译器警告:负值左移

compiler warning: left shift of negative value

我认为 GCC 错误地产生了 [-Wshift-negative-value] 警告。

我有一个函数应该生成由其单个输入参数提供的一定长度的后缀掩码:

#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。但是我已经在 godbolt 上使用最新的 GCC 9.x 版本进行了尝试,它们都产生了相同的警告。然而,Clang 版本不会产生此错误。

警告正确。

~((uint16_t) 0) 产生负值,因为 (uint16_t) 0 的结果在执行按位补码之前被提升为 int

一般来说,在使用位移位时,您应该更喜欢无符号整数(足够宽以避免类型提升)。我的建议是使用 unsigned int 零代替:

return (~(~0U << shift));

当小于 int 的变量(例如 uint16_t)与按位补码运算符 ~ 一起使用时,它们是 promoted to int.

类型 int 是有符号的,不能很好地进行移位。特别是考虑到 ~0 将是 -1 与补码符号(这是二进制系统中表示负数的最常见符号)。

一种可能的解决方案是使用较大的无符号类型(如 unsigned int),然后在完成后使用掩码获取较小类型的相关位。