pack
pragma
指定结构、联合和类成员的封装对齐。
语法
#pragma pack( show )
#pragma pack( push
[ ] [,
identifier
] ],
n
)
#pragma pack( pop
[,
{identifier
|n
} ])
#pragma pack(
[n
])
参数
show
(可选)显示封装对齐的当前字节值。 该值由警告消息显示。
push
(可选)将当前封装对齐值推送到内部编译器堆栈上,并将当前封装对齐值设置为 n。 如果未指定 n,则将推送当前封装对齐值。
pop
(可选)从内部编译器堆栈的顶部移除记录。 如果没有用 pop
指定 n,则与堆栈顶部的生成的记录关联的封装值是新的封装对齐值。 如果指定了 n(例如 #pragma pack(pop, 16)
),n 将成为新的封装对齐值。 如果使用 identifier
(例如 #pragma pack(pop, r1)
)进行弹出,则堆栈上的所有记录都将弹出,直到找到包含 identifier
的记录。 该记录将会弹出,与堆栈顶部发现的记录关联的封装值成为新的封装对齐值。 如果使用在堆栈上的任何记录中均未发现的 identifier
进行弹出,则会忽略 pop
。
该语句 #pragma pack (pop, r1, 2)
等效于 #pragma pack (pop, r1)
后跟 #pragma pack(2)
。
identifier
(可选)当与 push
一起使用时,为内部编译器堆栈上的记录指定名称。 与 pop
一起使用时,会从内部堆栈弹出记录,直到删除 identifier
。 如果在内部堆栈上未发现 identifier
,则不会弹出任何内容。
n
(可选)指定要用于封装的值(以字节为单位)。 如果没有为模块设置编译器选项 /Zp
,n
的默认值为 8。 有效值为 1、2、4、8 和 16。 成员在作为 n
的倍数或成员的大小的倍数的边界(以较小者为准)上对齐。
注解
pack 类是将其成员直接逐一放在内存中。 这可能意味着,某些或全部成员可在小于目标体系结构的默认对齐的边界上对齐。 pack
提供了数据声明级别的控制。 它与编译器选项 /Zp
不同,该选项只提供模块级别控制。 在 pragma 出现之后,pack 在第一个 struct
、union
或 class
声明处生效。 pack
对定义没有影响。 在没有参数的情况下调用 pack
会将 n
设置为编译器选项 /Zp
中设置的值。 如果未设置编译器选项,则 x86、ARM 和 ARM64 的默认值为 8。 对于 x64 本机和 ARM64EC,默认值为 16。
如果更改结构的对齐方式,它可能不会占用太多内存空间。 但是,对于未对齐的访问,可能会看到性能丢失,甚至会引发硬件生成的异常。 可以使用 SetErrorMode
修改此异常行为。
有关如何修改对齐方式的详细信息,请参阅以下文章:
-
警告
在 Visual Studio 2015 和更高版本中,可使用标准的
alignas
和alignof
运算符,这不同于__alignof
和__declspec( align )
,它们是跨编译器可移植的。 C++ 标准不能解决封装,因此仍必须使用pack
(或其他编译器上相应的扩展)来指定小于目标体系结构字体大小的对齐方式。
示例
以下示例演示如何使用 pack
pragma 更改结构的对齐方式。
// pragma_directives_pack.cpp
#include <stddef.h>
#include <stdio.h>
struct S {
int i; // size 4
short j; // size 2
double k; // size 8
};
#pragma pack(2)
struct T {
int i;
short j;
double k;
};
int main() {
printf("%zu ", offsetof(S, i));
printf("%zu ", offsetof(S, j));
printf("%zu\n", offsetof(S, k));
printf("%zu ", offsetof(T, i));
printf("%zu ", offsetof(T, j));
printf("%zu\n", offsetof(T, k));
}
0 4 8
0 4 6
以下示例演示如何使用 push、pop 和 show 语法。
// pragma_directives_pack_2.cpp
// compile with: /W1 /c
#pragma pack() // n defaults to 8; equivalent to /Zp8
#pragma pack(show) // C4810
#pragma pack(4) // n = 4
#pragma pack(show) // C4810
#pragma pack(push, r1, 16) // n = 16, pushed to stack
#pragma pack(show) // C4810
// pop to the identifier and then set
// the value of the current packing alignment:
#pragma pack(pop, r1, 2) // n = 2 , stack popped
#pragma pack(show) // C4810