C++ 神秘结构赋值与 int 截断

C++ Mystic structure assignment with int truncated

我有以下代码 (c++11) :

#include <iostream>

using namespace std;

//Icons
typedef struct
{
    union
    {
        struct
        {
            uint8_t a  : 1;
            uint8_t b  : 1;
            uint8_t c  : 1;
            uint8_t : 5;
        };
        uint8_t Data;
    } Bla;

    union
    {
        struct
        {
            uint8_t d  : 1;
            uint8_t e  : 1;
            uint8_t : 6;
        };
        uint8_t Data;
    } Foo;

    union
    {
        struct
        {
            uint8_t f   : 1;
            uint8_t g   : 1;
            uint8_t h   : 1;
            uint8_t i   : 1;
            uint8_t : 4;
        };
        uint8_t Data;
    } Bar;
}TypeStruct;

int main()
{

    static constexpr TypeStruct NONE    = {0x00,0,0}; 
    static constexpr TypeStruct A =       {0x01,0,0};    
    static constexpr TypeStruct B   =     {0x02,0,0};     
    static constexpr TypeStruct C     =   {0x04,0,0};    

   return 0;
}

在 IAR 上编译和工作正常,但在迂腐的 GCC 下,我收到以下错误,这困扰了我几天...

$g++ -std=c++11 -o main *.cpp
main.cpp: In function ‘int main()’:
main.cpp:50:52: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     static constexpr TypeStruct B   =     {0x02,0,0};
                                                    ^
main.cpp:51:52: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     static constexpr TypeStruct C     =   {0x04,0,0};
                                                    ^

我不明白为什么! 也许与 union 有关,但我尝试了不同的着作,但没有匹配: {1,0,0} 或 {{1},{0},{0}} 或 {{1,0,0}} 问题是我需要在专业化中使用类似 "A" 的东西,并且无法更改,比方说:

MyClass:MyMotherClass(TypeStruct A);

谢谢


编辑: 选择的解决方案是使用:

static constexpr TypeStruct A   =   {{1,0,0},{0,0},{0,0,0,0}};     
static constexpr TypeStruct B   =   {{0,1,0},{0,0},{0,0,0,0}};      
static constexpr TypeStruct C   =   {{0,0,1},{0,0},{0,0,0,0}};  
etc...

然而,使用这个像 IAR 和 GCC 一样编译的解决方案,我得到以下 PC lint 消息,优先级:高,类别:4397。

 "pc lint constexpr variable 'A' must be initialized by a constant expression"
 "pc lint constexpr variable 'B' must be initialized by a constant expression"
 "pc lint constexpr variable 'C' must be initialized by a constant expression"

正在对位域结构应用初始化,因为它首先在联合中声明。 (将 uint8_t 数据成员放在第一位,警告就会消失)。结果 0x02 和 0x04 对于第一个成员 (uint8_t a) 来说太大了。

您可以通过显式指定位域初始化来解决此问题,例如

static constexpr TypeStruct B   =   {{0,1},0,0};     
static constexpr TypeStruct C   =   {{0,0,1},0,0};    

请注意,一般来说,不能保证位域对应于字节(或其他整数类型)中的位位置 - 这取决于编译器。因此,使用字节值(如 0x02 和 0x04)直接初始化位域结构一开始并不是一个好主意。

使用 IAR 和 GCC 编译代码并避免 PC-lint 错误 #4397 的解决方案:

应使用

static const 而不是 static constexpr

static const TypeStruct A   =   {{1,0,0},{0,0},{0,0,0,0}};     
static const TypeStruct B   =   {{0,1,0},{0,0},{0,0,0,0}};      
static const TypeStruct C   =   {{0,0,1},{0,0},{0,0,0,0}};      
static const TypeStruct D   =   {{0,0,1},{1,0},{0,0,0,0}}; 
etc...