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 pack
:https://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 个字节的对齐方式打包结构。
为什么带有位字段的结构的大小不是我所期望的。
#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 pack
:https://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 个字节的对齐方式打包结构。