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
编译一个项目,但遇到了一种情况,即无法让编译器相信我已经完成了转换。
In case 1, I'm using the same solution proposed in c++ bit fields and -Wconversion and it works great. It forces the compiler to accept the conversion because of the bitmask which limits value's range.
In case 2, however, because of the shift (but why?) the compiler refuses to accept the conversion. And complains in the following way:
$ 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
(Interesting note: with clang the code compiles without issues. I've observed so far that clang's
-Wconversion
is much less stricter than GCC's.)
问题:
- 我该如何说服GCC编译第二种情况?
- 同时,为什么右移操作会改变所有内容呢?在我的理解中,对于一个
unsigned int
类型的表达式,位移操作不应该改变它的类型。 - 最后,这可能是编译器的bug吗?
注[1]:此问题与c++ bit fields and -Wconversion不重复,因为那里提出的解决方案在我的情况下根本不起作用。
注[2]:此问题与Why >>24 causes -Wconversion but >>23 doesn't?不重复,因为它涉及到一个不同的bug(或者是相同核心bug的不同表现),并且有一个简单的解决方法,就像c++ bit fields and -Wconversion中提出的那样,至少在GCC 7.3中可以使用强制转换来解决。