我正在尝试将现有应用程序从 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位的宽度和属性packed被添加到数据整数以将整数的宽度限制为三个字节。然后我可以像这样使用像素中的数据:
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)进行编译时如何保留功能?