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
编译项目,但遇到无法使编译器确信转换良好的情况。$ 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的严格得多。)问题:
unsigned int
类型的表达式,移位操作不应更改其类型。 注意[1]::这个问题是,而不是,它是c++ bit fields and -Wconversion的重复项
因为在那里提出的解决方案对我而言根本行不通。
注意[2] :此问题是,而不是,它是以下项的重复项:
Why >>24 causes -Wconversion but >>23 doesn't?因为是指不同的错误(或同一核心错误的不同表现形式),并且至少在GCC 7.3中使用c++ bit fields and -Wconversion中提出的类型转换具有简单的解决方法。
最佳答案
我刚刚发现,在GCC的错误跟踪器中,有几个与-Wconversion
相关的错误。特别是:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170
具体来说,注释#18
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39170#c18)报告了与我的示例几乎相同的示例:
#include <stdint.h>
struct foo
{
unsigned bar: 30;
unsigned fill: 2;
};
struct foo test(uint32_t value)
{
struct foo foo;
foo.bar = (value >> 2) & 0x3fffffffU;
return foo;
}
因此,我相信这个问题绝对是 gcc错误。
个人解决方法
鉴于编译器的错误,我个人的解决方法是将正确的移位操作包装在
static
always_inline
函数中,即使我对此hack并不特别满意。#include <stdint.h>
static __attribute__((always_inline)) inline uintptr_t
rshift(uintptr_t val, uintptr_t bits)
{
return val >> bits;
}
int main() {
struct { unsigned int a:20; } s;
unsigned int val = 0xaabbc000;
s.a = val & 0xfffff; // 1) works
s.a = (rshift(val, 12)) & 0xfffff; // 2) works
}
PSkocik建议的解决方法
s.a = (unsigned){(val >> 12)} & 0xfffff; // works
到目前为止,这是我的最爱。