如何为包含32位的位字段分配32位无符号整数

时间:2019-08-15 21:55:40

标签: c++ bit-fields

我试图创建一个总共有32位的位域结构,但是当我尝试为其分配32位数字时,出现此错误:

  

从“无符号整数”到位字段的隐式截断将值从4278190080更改为0

这是我的结构以及如何使用它

struct Color32 {
    uint32_t a : 8;
    uint32_t r : 8;
    uint32_t g : 8;
    uint32_t b : 8;
};


Color32 BLACK = {0xFF000000}; // this line has the compilation error

我在位域分配周围看到other questions,但它们似乎都使用按位运算来设置各个字段。

还有this reference,它具有以下示例,这似乎与我使用的示例相同,只是我的不会编译:

#include <iostream>
struct S {
 // three-bit unsigned field,
 // allowed values are 0...7
 unsigned int b : 3;
};
int main()
{
    S s = {6};
    ++s.b; // store the value 7 in the bit field
    std::cout << s.b << '\n';
    ++s.b; // the value 8 does not fit in this bit field
    std::cout << s.b << '\n'; // formally implementation-defined, typically 0
}

4 个答案:

答案 0 :(得分:6)

您可以在此处使用aggregate initialization

Color32 BLACK = {0xFF, 0x00, 0x00, 0x00};

顺便说一句,我建议将您的Color32结构修改为以下结构,这与指定成员的bit字段具有相同的作用

struct Color32 {
    uint8_t a;
    uint8_t r;
    uint8_t g;
    uint8_t b;
};

答案 1 :(得分:3)

这样的事情可以给你两全其美的感觉:

bit field

与此有关的一个问题是,结构中a,b,g,r的顺序可能取决于您的特定编译器。对于VS2017编译为Windows目标,显示的顺序将产生预期的结果。我相信也许可以通过某种方式强制执行该命令,但是我对如何执行该命令并不熟悉。

答案 2 :(得分:0)

位域与否,您的类型具有四个成员,而不是一个。

您似乎正在尝试将其视为工会。

您可以像对待其他任何类型一样分别初始化每个成员,或者切换到并集(然后像往常一样,请像许多人一样依赖于类型处理)。


您提供的反例是不同的,因为它是在初始化器中具有单个成员和单个值的UDT。由于参加比赛的成员人数众多,所以一切都很好。

答案 3 :(得分:0)

在深入探讨该主题之后,我发现如果没有按位运算符和有效的构造函数,多个位字段将无用,因为它在很大程度上取决于操作系统。

答案已在Windows 7上的cygwin(-Wno-unused-variable -O0 -ggdb标志)上进行了测试

  

版本1: union

这是没有任何位字段的基本实现,是4字节颜色空间的最常见实现。

#include <iostream>  

union c_space32{
    uint32_t space;
    uint8_t channels[4];
};

int main(){

    { // just a anonymous scope to keep things clear 
        union c_space32 temp = {0xff00fe32};
        std::cout << "sizeof : " << sizeof( union c_space32 ) << "\n\n";
        std::cout << (int)temp.channels[1] << "\t" << std::hex << temp.space <<  "\n";
        ++temp.channels[1];
        std::cout << (int)temp.channels[1] << "\t" << std::hex << temp.space <<  "\n";
        ++temp.channels[1];
        std::cout << (int)temp.channels[1] << "\t" << std::hex << temp.space <<  "\n";
    }

return 0;}  

联合的行为就像普通的色彩空间,联合的每个uint8_t部分的行为都是唯一的字节,因此c_space32.channels中值的整体变化不会影响c_space32.space的值超出字节范围。这是我得到的输出。

sizeof : 4
fe  ff00fe32
ff  ff00ff32
0   ff000032  
  

版本2: bit-fields

位域的问题(在某些情况下缺少文档)是它们可以轻松更改大小,并且字节顺序取决于OS,因此位域结构背后的本机逻辑可以逃避我们的人工逻辑。让我给您提供一些示例,供将来希望参与此主题的家伙/女孩使用。

#include <iostream> 
#include <bitset> 

struct temp1{
    uint8_t a:1;
    temp1(uint8_t val){ // just so i can assign it
        this->a = (val & 0x1 ); // this is needed to avoid truncated warning
    }
};

int main(){
    struct temp1 t1 = 3;
    uint8_t *ptr = (uint8_t *)&t1;
    std::cout << sizeof(struct temp1) << std::endl; // size of 1 byte
    std::cout << std::bitset<8>( *ptr ) << std::endl; // 0000-0001 position of our bitfield
return 0;}

因此,在这种情况下,sizeof(struct temp1)返回的大小为1 byte 。以我们的位字段的位置为最右边。这就是MIA文档开始使用的地方。

#include <iostream> 
#include <bitset> 

struct temp2{
    uint8_t a:1;
    uint8_t b:1;
    uint8_t c:1;
    temp2(int VAL){ // just so i can assign it
        this->a = (VAL & 0x1 );
        this->b = 0;
        this->c = (VAL >> 2 ) & 0x1;
    }
};

int main(){
    struct temp2 t1 = 0xf;
    uint8_t *ptr = (uint8_t *)&t1;
    std::cout << sizeof(struct temp2) << std::endl; // size of 1
    std::cout << std::bitset<8>( *ptr ) << std::endl; // 0000-0101
return 0;}

在这种情况下,constructor必须拥有的,因为计算机不知道您要如何构造数据。可以肯定的是,如果我们对位进行排队,则逻辑上分配它们与共享内存是相同的。但是问题是计算机不会为我们bitwise operators做。确保这些位是按顺序排列并自然排列的,但计算机只是抓住了一些位并将其定义为唯一变量,您可以选择将其放置在该变量中。

如果我们超出了 unit memory size(字节)的范围,则OS开始干扰我们的工作。

#include <iostream> 
#include <bitset> 

struct temp3{
    bool b0:1;
    bool b1:1;
    bool b2:1;
    bool b3:1;
    bool b4:1;
    bool b5:1;
    bool b6:1;
    bool b7:1;

    temp3( int a ){
        this->b0 = ( a & 0x1 );
        this->b1 = ( a & 0x2 );
        this->b2 = ( a & 0x4 );
        this->b3 = ( a & 0x8 );
        this->b4 = ( a & 0x10 );
        this->b5 = ( a & 0x20 );
        this->b6 = ( a & 0x40 );
        this->b7 = ( a & 0x80 );
    }

};

int main(){
    struct temp3 t1 = 0xc3;
    uint8_t *ptr = (uint8_t *)&t1;
    std::cout << sizeof(struct temp3) << std::endl; // still size of 1
    std::cout << std::bitset<8>( *ptr ) << std::endl; // 1100-0011
return 0;}  

当我们超过字节大小时:

#include <iostream> 
#include <bitset> 
struct temp4{
    bool b0:1;
    bool b1:1;
    bool b2:1;
    bool b3:1;
    bool b4:1;
    bool b5:1;
    bool b6:1;
    bool b7:1;
    bool b8:1;

    temp4( int a ){
        this->b0 = ( a & 0x1 );
        this->b1 = ( a & 0x2 );
        this->b2 = ( a & 0x4 );
        this->b3 = ( a & 0x8 );
        this->b4 = ( a & 0x10 );
        this->b5 = ( a & 0x20 );
        this->b6 = ( a & 0x40 );
        this->b7 = ( a & 0x80 );
        this->b8 = ( a & 0x100 );
    }

};

int main(){
    struct temp4 t1 = 0x1c3;
    uint16_t *ptr = (uint16_t *)&t1;
    std::cout << sizeof(struct temp4) << std::endl; // size of 2
    std::cout << std::bitset<16>( *ptr ) << std::endl; // 0000-0000 1100-0011
    std::cout << t1.b8 << std::endl; // still returns 1
    std::cout << "\n\n";

    union t_as{
        uint16_t space;
        temp4 data;
        uint8_t bytes[2];
    };

    union t_as t2 = {0x1c3};
    //11000011-00000001
    std::cout << std::bitset<8>( t2.bytes[0] ) << "-"  << std::bitset<8>( t2.bytes[1] ) << std::endl;
return 0;}  

这里发生了什么?由于我们添加了另一个 bool bit-field ,因此我们的结构增长了1个字节(因为bool是1个字节),而我们的16位指针却没有显示最后一个b8-但联合会显示。问题是操作系统接管了,在这种情况下,由于固有的OS字节顺序,最后一丝滞后了我们的原始内存。如您在联合中所看到的,字节仍然被读取,但是顺序不同。

  

因此,当超出字节大小时,将应用常规OS规则。

结论和答案

struct half_opacity{
    uint8_t alpha:4;
    uint8_t red;
    uint8_t green;
    uint8_t blue;
    half_opacity(int a){
        this->alpha = ( a >> 24 )&0xf;
        this->red   = ( a >> 16 )&0xff;
        this->green = ( a >> 8  )&0xff;
        this->blue  = ( a & 0xff );
    }
    operator uint32_t(){
        return      ( this->alpha << 24 )
                |   ( this->red   << 16 )
                |   ( this->green << 8 )
                |   this->blue;
    }
};

{
    struct half_opacity c_space = 0xff00AABB;
    std::cout << "size of : " << sizeof(struct half_opacity) << std::endl; //size of : 4
    std::cout << std::hex << (uint32_t)c_space << std::endl; // 0x0f00AABB  
}

因此,除非您打算将原始通道分配给某个位大小,否则我强烈建议使用union方法,因为使用{{1将32位整数拆分为单个字节没有任何其他好处。 }}。关于bit-fields的主要问题是,您需要将它们拆分并进行构建,然后像其他任何整数字段一样进行备份-bit fields通常会绕过整个OS字节序。

您得到的截断警告是由于您的结构中有多个成员,并且该结构自然地分配了第一个成员,并且由于您添加的bit shifts超出了编译器的处理能力,因此警告您某些数据将丢失。

相关问题