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

我试图将现有的应用程序从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通道。

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

 #include  #include  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)等,但我发现没有组合将我的struct打包为三个字节的大小。

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

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

这个问题的答案和这个问题提到了“实现定义”的位填充,并导致这个官方的MSVC文档页面说:

相邻的位字段被打包到相同的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()不兼容,至少直接。