编译器警告:负值左移

问题描述 投票:0回答:2

我认为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版本不会产生此错误。

c gcc gcc-warning
2个回答
3
投票

警告正确。

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

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

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

5
投票

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

类型int是带符号的,在移位时不能很好地工作。尤其要考虑到int将是带有二进制补码的~0(这是表示二进制系统上负数的最常见的表示法)。

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

© www.soinside.com 2019 - 2024. All rights reserved.