【问题标题】:Define an enum to be smaller than one byte / Why is this struct larger than one byte?定义一个小于一个字节的枚举/为什么这个结构大于一个字节?
【发布时间】:2013-06-11 20:56:47
【问题描述】:

我想定义一个小于一个字节的枚举,同时保持类型安全。

将枚举定义为:

enum MyEnum : unsigned char
{
    i ,j, k, w
};

我可以将它缩小到一个字节,但是我想让它只使用 2 位,因为我最多会有 4 个值。这个可以吗?

在我使用枚举的结构中,以下内容不起作用

struct MyStruct
{
    MyEnum mEnum : 2; // This will be 4 bytes in size
};

谢谢!

更新:

问题来自这个场景:

enum MyEnum : unsigned char
{
    i ,j, k, w
};

struct MyStruct
{
    union
    {
        signed int mXa:3;
        unsigned int mXb:3;
    };

    union
    {
        signed int mYa:3;
        unsigned int mYb:3;
    };

    MyEnum mEnum:2;
};

sizeof(MyStruct) 显示 9 个字节。理想情况下,我希望结构的大小为 1 个字节。

已实施解决方案的更新:

这个结构是一个字节,提供相同的功能和类型安全:

enum MyEnum :unsigned char
{
   i,j,k,w
};

struct MyStruct
{
   union
   {
      struct { MyEnum mEnum:2; char mXa:3; char mXb:3;};
      struct { MyEnum mEnum:2; unsigned char mYa:3; unsigned char mYb:3;};
   }; 
};

【问题讨论】:

  • 不。最好的选择是使用位域,但在 C++ 中,不小于一个字节本身是可寻址的。
  • 您到底想解决什么问题?提供一些上下文可能有助于揭示设计缺陷或更好的解决方案。
  • 我正在尝试尽可能地缩小结构以应对挑战,但我不明白为什么不能这样做,因此结构不大于 1 个字节。

标签: c++ optimization enums standards


【解决方案1】:

根据标准定义,sizeof 类型必须至少为 1 个字节。这是最小的可寻址内存单元。

您提到的位域的功能允许将结构的成员定义为具有较小的大小,但结构本身可能不是因为

  • 它也必须至少有 1 个字节
  • 对齐考虑可能需要更大

此外,您可能不会获取位域成员的地址,因为如上所述,一个字节是内存的最小可寻址单元(您已经可以看到sizeof实际上返回的是字节数,而不是位,所以如果你预计不到CHAR_BIT 位,sizeof 甚至无法表达)。

【讨论】:

  • 当然,但我不太清楚为什么(在我更新的问题中)现在枚举是一个有点打包的结构的成员,大小急剧膨胀。
  • @mrantifreeze:我不知道您所说的“位压缩结构”到底是什么意思,但也许您正在寻找像 gccs [[packed]] 属性这样的编译器扩展?我会假设大多数编译器都给联合体提供了无符号/有符号的对齐要求,这将使那些填充为 3 倍无符号 = 12 个字节。
  • @PlasmaHH:小心,他的工会有一个sizeof(4),但对齐只有1:D
【解决方案2】:

位域只有在使用相同的底层类型时才能共享空间。并且任何未使用的位实际上都未使用;如果unsigned int 位域中的位总和为 3 位,则仍需要 4 个字节总计。由于两个枚举都有unsigned int 成员,它们都是4 个字节,但由于它们是位域,它们的对齐方式为1。所以第一个enum是4个字节,第二个是4个字节,那么MyEnum是1个字节。由于所有这些都有一个对齐,因此不需要填充。

不幸的是,union 根本不能真正用于位域。位域仅适用于整数类型。如果不进行认真的重新设计,我最多可以获得 3 个字节:http://coliru.stacked-crooked.com/view?id=c6ad03c93d7893ca2095fabc7f72ca48-e54ee7a04e4b807da0930236d4cc94dc

enum MyEnum : unsigned char
{
    i ,j, k, w
};

union MyUnion
{
    signed char ma:3; //char to save memory
    unsigned char mb:3;
};

struct MyStruct
{
    MyUnion X;
    MyUnion Y; 
    MyEnum mEnum;
}; //this structure is three bytes

在完整的重新设计类别中,您有这个:http://coliru.stacked-crooked.com/view?id=58269eef03981e5c219bf86167972906-e54ee7a04e4b807da0930236d4cc94dc

【讨论】:

  • 对于快速阅读者,您应该提到代码无法编译。
  • @PlasmaHH 哦,是的,我在MyStruct 中有错字。固定的。谢谢。
【解决方案3】:

没有。 C++ 将“char”定义为平台的最小可寻址内存单元。你不能寻址 2 位。

【讨论】:

    【解决方案4】:

    位包装“为我工作”

    #include <iostream>
    
    enum MyEnum : unsigned char
    {
        i ,j, k, w
    };
    struct MyStruct
    {
        MyEnum mEnum : 2;
        unsigned char val : 6;
    };
    
    int main()
    {
        std::cout << sizeof(MyStruct);
    }
    

    打印出 1. 您如何/测量什么?

    编辑:Live link

    您是否正在做类似在结构中使用指针作为下一步的事情?在这种情况下,您将拥有 30 位的死区,因为在大多数 32 位系统上,指针必须是 4 字节对齐的。

    编辑:使用您更新的示例,它的工会正在破坏您

    enum MyEnum : unsigned char
    {
        i ,j, k, w
    };
    
    
    struct MyStruct
    {
        unsigned char mXb:3;
        unsigned char mYb:3;
    
        MyEnum mEnum:2;
    };
    

    尺寸为 1。但我不确定联合和位包装如何协同工作,所以我没有更多帮助。

    【讨论】:

    • 位打包仅适用于整数类型。联合不是整数类型。很遗憾,他们根本不合作。 :(
    猜你喜欢
    • 2021-05-19
    • 2019-06-27
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多