#pragma pack(8) 应该如何工作?
How should #pragma pack(8) work?
我不熟悉结构对齐和打包。我以为我明白了,但我发现了一些我没想到的结果(见下文)。
我对结构对齐的理解是:
类型通常在内存地址上对齐,内存地址是其大小的倍数。
根据需要添加填充以促进正确对齐
结构的末尾必须填充到最大元素的倍数(以方便数组访问)
#pragma pack
指令基本上允许覆盖基于类型大小对齐的一般约定:
#pragma pack(push, 8)
struct SPack8
{
// Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
short int a;
double b;
short int c;
int d;
};
#pragma pack(pop)
Pseudo struct layout: What I expected:
// note: PADDING IS BRACKETED
0, 1, [2, 3, 4, 5, 6, 7] // a occupies address 0, 1
8, 9, 10, 11, 12, 13, 14, 15, // b occupies 8-15 inclusive
16, 17, [18, 19, 20, 21, 22, 23] // c occupies 16-17 inclusive
24, 25, 26, 27 // d occupies 24-27 inclusive
// Thus far, SPack8 is 28 bytes, but the structure must be a multiple of
// sizeof(double) so we need to add padding to make it 32 bytes
[28, 29, 30, 31]
令我惊讶的是,VS 2015 x86 上的 sizeof(SPack8) == 24。似乎 d 没有在 8 字节地址上对齐:
offsetof(SPack, a) // 0, as expected
offsetof(SPack, b) // 8, as expected
offsetof(Spack, c) // 16, as expected
offsetof(SPack, d) // 20..what??
谁能解释一下happening/what我误解了什么?
谢谢!
您的误解是 #pragma pack
让您 加宽 结构,但事实并非如此。 pack
允许您在需要时更紧密地 打包 结构。 #pragma pack(push, 8)
告诉编译器,它可以 最多 在 8 字节边界上对齐,但 不能更多 。
示例:
#pragma pack(push, 2)
struct X {
char a; // 1 byte
// 1 byte padding
int b; // 4 bytes, note though that it's aligned on 2 bytes, not 4.
char c, d, e; // 3 bytes
//1 byte padding
}; // == 10 bytes, the whole struct is also aligned on 2 bytes, not 4
#pragma pack(pop)
// The same struct without the pragma pack:
struct Y {
char a; // 1 byte
// 3 bytes padding
int b; // 4 bytes
char c, d, e; // 3 bytes
// 1 byte padding
};
这就是 pack
所做的,使用编译器通常使用的 less 填充。在您的示例中,您尝试在 8 字节边界上对齐 int
,但由于您允许编译器在 至多 8 个字节上对齐,因此编译器 [=4 字节对齐 想用就好了。大小为 24 的整个结构的大小也为 8 的倍数(最大成员),因此无需填充即可将其填充到 32。
您可以强行对齐您的结构
__declspec(align(32)) struct Z {
char a;
int b;
char c, d, e;
};
甚至是您的结构的成员
struct SPack8
{
// Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
short int a;
double b;
short int c;
__declspec(align(8)) int d;
};
在特定边界上,但我看不出有什么理由强制 4 字节类型在 8 字节上对齐。
我不熟悉结构对齐和打包。我以为我明白了,但我发现了一些我没想到的结果(见下文)。
我对结构对齐的理解是:
类型通常在内存地址上对齐,内存地址是其大小的倍数。
根据需要添加填充以促进正确对齐
结构的末尾必须填充到最大元素的倍数(以方便数组访问)
#pragma pack
指令基本上允许覆盖基于类型大小对齐的一般约定:
#pragma pack(push, 8)
struct SPack8
{
// Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
short int a;
double b;
short int c;
int d;
};
#pragma pack(pop)
Pseudo struct layout: What I expected:
// note: PADDING IS BRACKETED
0, 1, [2, 3, 4, 5, 6, 7] // a occupies address 0, 1
8, 9, 10, 11, 12, 13, 14, 15, // b occupies 8-15 inclusive
16, 17, [18, 19, 20, 21, 22, 23] // c occupies 16-17 inclusive
24, 25, 26, 27 // d occupies 24-27 inclusive
// Thus far, SPack8 is 28 bytes, but the structure must be a multiple of
// sizeof(double) so we need to add padding to make it 32 bytes
[28, 29, 30, 31]
令我惊讶的是,VS 2015 x86 上的 sizeof(SPack8) == 24。似乎 d 没有在 8 字节地址上对齐:
offsetof(SPack, a) // 0, as expected
offsetof(SPack, b) // 8, as expected
offsetof(Spack, c) // 16, as expected
offsetof(SPack, d) // 20..what??
谁能解释一下happening/what我误解了什么?
谢谢!
您的误解是 #pragma pack
让您 加宽 结构,但事实并非如此。 pack
允许您在需要时更紧密地 打包 结构。 #pragma pack(push, 8)
告诉编译器,它可以 最多 在 8 字节边界上对齐,但 不能更多 。
示例:
#pragma pack(push, 2)
struct X {
char a; // 1 byte
// 1 byte padding
int b; // 4 bytes, note though that it's aligned on 2 bytes, not 4.
char c, d, e; // 3 bytes
//1 byte padding
}; // == 10 bytes, the whole struct is also aligned on 2 bytes, not 4
#pragma pack(pop)
// The same struct without the pragma pack:
struct Y {
char a; // 1 byte
// 3 bytes padding
int b; // 4 bytes
char c, d, e; // 3 bytes
// 1 byte padding
};
这就是 pack
所做的,使用编译器通常使用的 less 填充。在您的示例中,您尝试在 8 字节边界上对齐 int
,但由于您允许编译器在 至多 8 个字节上对齐,因此编译器 [=4 字节对齐 想用就好了。大小为 24 的整个结构的大小也为 8 的倍数(最大成员),因此无需填充即可将其填充到 32。
您可以强行对齐您的结构
__declspec(align(32)) struct Z {
char a;
int b;
char c, d, e;
};
甚至是您的结构的成员
struct SPack8
{
// Assume short int is 2 bytes, double is 8 bytes, and int is 4 bytes
short int a;
double b;
short int c;
__declspec(align(8)) int d;
};
在特定边界上,但我看不出有什么理由强制 4 字节类型在 8 字节上对齐。