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编译项目,但遇到无法使编译器确信转换良好的情况。
  • 在第一种情况下,我使用的是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?因为是指不同的错误(或同一核心错误的不同表现形式),并且至少在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
    

    到目前为止,这是我的最爱。

    09-25 21:29