C++ 中带有位字段的结构的大小不相加

Size of struct with bit fields in C++ not adding up

为什么带有位字段的结构的大小不是我所期望的。

#include <iostream>
using namespace std;

struct test {
    uint8_t x : 4;
    uint16_t y : 8;
    uint16_t z : 8;
};

struct test2 {
    uint8_t x : 4;
    uint16_t y : 10;
    uint16_t z : 10;
};

int main()
{
  cout << sizeof(test) << endl;
  cout << sizeof(test2) << endl;
}

这将打印 4 和 4。 我不明白为什么这两个的大小都不是 3。测试有 4+8+8 位,即 20,测试 2 有 4+10+10 位,即 24 位,均小于或等于 24 bits/3 字节。我知道如果在测试中我使用 uint_8 它会导致大小为 3 但对于我的实际用例我需要 Test2(4,10,10 位)。为什么会这样,有没有办法让它达到 3 个字节?

Why is this

std::uint16_t 大概对您的系统有 2 的对齐要求。因此,可以放置成员的第一个有效偏移量是第三个字节(2 的偏移量可被对齐整除)。由于第二个字节(偏移量1)没有可以存储的东西,因此它是无用的填充。

is there a way to get this to 3 bytes?

不,没有标准方法可以使 test2 达到 3 个字节。对于 test,对所有成员使用 std::uint8_t 很容易。

也可能没有必要将其设置为 3 个字节。如果您确实需要精确的位布局,那么对齐不是您唯一关心的问题,因为位域的布局在任何方面都不是标准的。

不仅是位域,所有结构都由编译器对齐以获得最大效率。如果你想将它们强制为最小大小,你需要使用 gcc 的属性 packed 或你正在使用的编译器中的等效属性,如下所示:

#include <iostream>
using namespace std;

struct test {
    uint8_t x : 4;
    uint16_t y : 8;
    uint16_t z : 8;
} __attribute__ ((packed));

struct test2 {
    uint8_t x : 4;
    uint16_t y : 10;
    uint16_t z : 10;
} __attribute__ ((packed));

int main()
{
  cout << sizeof(test) << endl;
  cout << sizeof(test2) << endl;
}

Data structure alignment 将帮助您解释输出:https://en.wikipedia.org/wiki/Data_structure_alignment

数据结构正在添加更多 space,称为填充。你还需要检查你的编译器,因为不同的编译器有不同的默认结构对齐选项,并且会有不同的输出,例如在VS中你可以在这里设置它:

此外,您可能需要查看 #pragma packhttps://docs.microsoft.com/en-us/cpp/preprocessor/pack?redirectedfrom=MSDN&view=msvc-160

#pragma pack( push, 1 )

struct test {
    uint8_t x : 4;
    uint16_t y : 8;
    uint16_t z : 8;
};

struct test2 {
    uint8_t x : 4;
    uint16_t y : 10;
    uint16_t z : 10;
};

#pragma pack( pop )

这将按 1 个字节的对齐方式打包结构。