[英]How to pack a struct in Visual Studio to 24 bits that contains an uint32_t?
I am trying to port over an existing application from a 32-Bit ARM-microcontroller to desktop plattforms such as Microsoft Windows. 我试图将现有应用程序从32位ARM微控制器移植到Microsoft Windows等桌面平台。 GCC is used on the ARM and I was able successfully compile the application on windows using a 32-bit MinGW-compiler, however I had no success using Microsoft's Visual Studio Compiler and that is the reason why I am asking here for help.
GCC用于ARM,我可以使用32位MinGW编译器在Windows上成功编译应用程序,但是我使用Microsoft的Visual Studio编译器没有成功,这就是我在这里寻求帮助的原因。
Here is what my application is doing: 这是我的应用程序正在做的事情:
I have some framebuffer consisting of three bytes per pixel, so my memory looks like RGBRGBRGB and so on. 我有一些每个像素三个字节组成的帧缓冲区,所以我的内存看起来像RGBRGBRGB等。 I use a DMA-Channel on the ARM to push the pixels out to the display and my display directly understands this memory layout.
我在ARM上使用DMA通道将像素推出显示器,并且我的显示器直接了解此内存布局。
I also want to save some CPU cycles so I want to use ARM's saturated ADD __UQADD8
to draw on my framebuffer, performing saturated add on all three channels using a single operation. 我还想节省一些CPU周期,所以我想使用ARM的饱和ADD
__UQADD8
绘制我的帧缓冲区,并使用单个操作在所有三个通道上执行饱和加法。
For this to work, I need all three channels to be available in a single integer to be used as argument to __UQADD8
. 为此,我需要所有三个通道都在单个整数中可用,以用作
__UQADD8
参数。
Thats the reason why I use a union for one pixel of my framebuffer offers access to the separate channels by providing a struct containing each of R,G,B as uint8_t and providing the same memory as a 24 bit wide integer labeled data: 这就是为什么我对帧缓冲区的一个像素使用并集的原因,因为它提供了一个包含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__));
}
The width of 24 bits and the attribute packed is added to the data integer to restrict the width of the integer to three bytes. 24位的宽度和打包的属性被添加到数据整数,以将整数的宽度限制为三个字节。 Then I can use the data in the pixel like this:
然后,我可以像这样使用像素中的数据:
Rgb Rgb::operator+(const Rgb & op) {
__UQADD8(data, op.data);
return Rgb(data);
}
Note that __UQADD8
magically does only write to three of the four bytes of my integer and does not alter the R-channel of the next RGB in my framebuffer. 请注意,
__UQADD8
神奇地仅写入了我的整数的四个字节中的三个字节,并且不会更改帧缓冲区中下一个RGB的R通道。
The following test program proves that my RGB's are all packed tight when using GCC: 以下测试程序证明了使用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;
}
To compile the example using MSVC, one has to remove the __attribute__packed. 要使用MSVC编译示例,必须删除__attribute__packed。 The program runs, but gives 4 as output.
该程序运行,但给出4作为输出。 There is number of other attributes in MSVC that can be used including
#pragma pack
, unaligned pointers __attribute__(aligned)
and so on, but I found no combination that packs my struct to a size of three bytes. MSVC中还有许多其他可以使用的属性,包括
#pragma pack
,未对齐的指针__attribute__(aligned)
等等__attribute__(aligned)
,但我发现没有组合可以将结构压缩为三个字节。
How to port my application to Microsoft's compiler while keeping functionality and preferable compatibility to GCC? 如何在保持功能和与GCC更好的兼容性的同时将我的应用程序移植到Microsoft的编译器?
Bonus question: How to keep functionality when compiling using a 64-bit compiler, either GCC or MSVC? 额外的问题:使用64位编译器(GCC或MSVC)进行编译时,如何保持功能?
The answer for this SO question and this question mention bit-packing being "implementation defined" and lead to this official MSVC documentation page which says: 这个SO问题和这个问题的答案都提到了“实现定义”的位打包,并导致该MSVC官方文档页面显示:
Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit...
相邻的位字段打包到相同的1、2或4字节分配单元中...
So it seems you cannot get an exact 3-byte bit field in MSVC. 因此,看来您无法在MSVC中获得确切的3字节位字段。 The only alternative I can think of is to do something like:
我唯一想到的替代方法是执行以下操作:
#pragma pack(push, 1)
union Rgb {
struct {
uint8_t r;
uint8_t g;
uint8_t b;
} ch;
unsigned char data[3];
};
#pragma pack(pop)
which will give you the desired 3-byte union size but may not be compatible with using __UQADD8(), at least directly. 这将为您提供所需的3字节联合大小,但至少与直接使用__UQADD8()可能不兼容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.