简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM