[英]How to pack a struct in Visual Studio to 24 bits that contains an uint32_t?
我试图将现有应用程序从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通道。
以下测试程序证明了使用GCC时,我的RGB都包装紧密:
#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)
等等__attribute__(aligned)
,但我发现没有组合可以将结构压缩为三个字节。
如何在保持功能和与GCC更好的兼容性的同时将我的应用程序移植到Microsoft的编译器?
额外的问题:使用64位编译器(GCC或MSVC)进行编译时,如何保持功能?
这个SO问题和这个问题的答案都提到了“实现定义”的位打包,并导致该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()可能不兼容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.