如何将Visual Studio中的结构打包为包含uint32_t的24位?

时间:2015-04-06 18:32:19

标签: c visual-studio struct unions bit-fields

我正在尝试将现有应用程序从32位ARM微控制器移植到桌面平台,例如Microsoft Windows。 GCC在ARM上使用,我能够使用32位MinGW编译器在Windows上成功编译应用程序,但是我没有成功使用Microsoft的Visual Studio编译器,这就是我在这里要求的原因救命。

这是我的应用程序正在做的事情:

我有一些帧缓冲,每个像素包含三个字节,因此我的内存看起来像RGBRGBRGB等等。 我在ARM上使用DMA通道将像素推出显示器,我的显示器直接了解这种内存布局。

我还想节省一些CPU周期,所以我想使用ARM的饱和ADD __UQADD8来绘制我的帧缓冲区,使用单个操作在所有三个通道上执行饱和加法。

为了实现这个目的,我需要在一个整数中使用所有三个通道作为__UQADD8的参数。

这就是我为帧缓冲区的一个像素使用联合的原因是通过提供包含R,G,B作为uint8_t的每个结构并提供与24位宽整数标记数据相同的内存来提供对单独通道的访问:

union Rgb {
    struct {
        uint8_t r;
        uint8_t g;
        uint8_t b;
    } ch;
    unsigned int data : 24 __attribute__((__packed__));
}

将24位宽度和打包属性添加到数据整数中,以将整数的宽度限制为三个字节。然后我可以使用像素中的数据:

Rgb Rgb::operator+(const Rgb & op) {
    __UQADD8(data, op.data);
    return Rgb(data);
}

请注意,__UQADD8神奇地只写入整数的四个字节中的三个,并且不会改变帧缓冲区中下一个RGB的R通道。

以下测试程序证明我的RGB在使用GCC时都是紧凑的:

#include <iostream>
#include <stdint.h>

union Rgb {
struct {
                uint8_t r;
                uint8_t g;
                uint8_t b;
        } ch;
    unsigned int data : 24 __attribute__((packed));
} ;

int main()
{
    std::cout << "Sizeof(Rgb) = "  << sizeof(Rgb) << std::endl;
    return 0;
}

要使用MSVC编译示例,必须删除__attribute__packed。程序运行,但输出为4。 MSVC中有许多其他属性可以使用,包括#pragma pack,未对齐的指针__attribute__(aligned)等等,但我发现没有组合将我的结构打包为三个字节的大小。

如何将我的应用程序移植到Microsoft的编译器,同时保持功能和与GCC的兼容性?

额外问题:如何在使用64位编译器(GCC或MSVC)编译时保留功能?

1 个答案:

答案 0 :(得分:3)

this SO questionthis question的答案提到了bit-packing is&#34;实现定义&#34;并导致this official MSVC documentation page说:

  

相邻位字段被打包到相同的1字节,2字节或4字节中   分配单位......

因此,似乎无法在MSVC中获得精确的3字节位字段。我能想到的唯一选择是做一些事情:

#pragma pack(push, 1)
union Rgb {
     struct {
          uint8_t r;
          uint8_t g;
          uint8_t b;
     } ch;
    unsigned char data[3];
};
#pragma pack(pop)

它将为您提供所需的3字节联合大小,但可能与使用__UQADD8()不兼容,至少是直接。