【问题标题】:How to pack a struct in Visual Studio to 24 bits that contains an uint32_t?如何将 Visual Studio 中的结构打包为包含 uint32_t 的 24 位?
【发布时间】:2015-04-06 18:32:19
【问题描述】:

我正在尝试将现有应用程序从 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)进行编译时保留功能?

【问题讨论】:

    标签: c visual-studio struct unions bit-fields


    【解决方案1】:

    this SO question 和 this question 的答案提到位打包是“实现定义的”并导致 this official MSVC documentation page 说:

    相邻的位域被打包成相同的 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() 不兼容,至少直接使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 2016-09-20
      • 2011-11-25
      • 2015-11-16
      相关资源
      最近更新 更多