【发布时间】:2019-01-29 13:04:14
【问题描述】:
int main() {
struct { unsigned int a:20; } s;
unsigned int val = 0xaabbc000;
s.a = val & 0xfffff; // 1) works
s.a = (val >> 12) & 0xfffff; // 2) generates -Wconversion warning
}
我正在使用 -Wconversion 编译一个项目,但遇到了一个无法让编译器相信我可以进行转换的情况。
在情况 1 中,我使用的是在 c++ bit fields and -Wconversion 中提出的相同解决方案,并且效果很好。它强制编译器接受转换,因为位掩码限制了值的范围。
-
然而,在情况 2 中,由于转换(但为什么?),编译器拒绝接受转换。并通过以下方式抱怨:
$ gcc wconv.c -Wconversion -Werror wconv.c: In function ‘main’: wconv.c:8:11: error: conversion to ‘unsigned int:20’ from ‘unsigned int’ may alter its value [-Werror=conversion] s.a = (val >> 12) & 0xfffff; // 2) generates -Wconversion warning ^ cc1: all warnings being treated as errors(有趣的说明:使用 clang 编译代码没有问题。到目前为止,我观察到 clang 的
-Wconversion比 GCC 的严格得多。)
问题:
- 如何说服 GCC 编译案例 2?
- 而且,为什么右移会改变一切?在我的理解中,给定一个具有
unsigned int类型的表达式,位移操作不应该改变它的类型。 - 最后,这可能是编译器错误吗?
注意[1]:这个问题不是重复的:c++ bit fields and -Wconversion 因为那里提出的解决方案对我来说根本不起作用。
注意[2]:这个问题不是重复的: Why >>24 causes -Wconversion but >>23 doesn't? 因为指的是 不同 错误(或相同核心错误的不同表现形式)并且有一个使用强制转换的简单解决方法,就像在 c++ bit fields and -Wconversion 中提出的那样,至少在 GCC 7.3 中。
【问题讨论】:
-
有趣的问题... 似乎 gcc 的逻辑中存在一些错误;掩码 0x7ffff 可以在没有警告的情况下工作 ;) 仅移动 11 位时也不会
-
@KrzysztofSzewczyk 警告不合适,因为之前应用了掩码,转换无法真正改变值
-
这似乎是由the same bug 引起的Why >>24 causes -Wconversion but >>23 doesn't?。这将与@Ctx 的观察结果一致,即在稍微调整掩码或移位时不会出现警告。