编译器警告:负值左移

Ari*_*ing 0 c gcc gcc-warning

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

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

#include <stdint.h>

uint16_t get_suffix_mask_sht(uint8_t shift) {
    return (~(~((uint16_t) 0) << shift));
}
Run Code Online (Sandbox Code Playgroud)

我试图在不同版本的gcc上使用以下编译器选项来编译此函数

-Werror -Wextra
Run Code Online (Sandbox Code Playgroud)

如果我改变输出从这个警告也发生uint16_tuint8_t。更大的输出类型,即uint32_t不产生此警告。

我使用的是旧版GCC:7.4。但是我已经使用最新的GCC 9.x版本在Godbolt上进行了尝试,它们都发出相同的警告。但是Clang版本不会产生此错误。

use*_*733 5

警告是正确的。

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

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

return (~(~0U << shift));
Run Code Online (Sandbox Code Playgroud)

  • @ArisKoning 不会起作用,因为整数提升也会对按位移位运算符的两个操作数进行。 (2认同)

Som*_*ude 5

当小于int(例如uint16_t)的变量与按位补数运算符~一起使用时,它们将提升为int

该类型int是带符号的,将不能很好地与移位配合使用。特别是考虑到~0-1与二进制补码(这是代表二进制系统负数的最常见的符号)。

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