Cprogramming 简明教程
Structure Padding and Packing in C
What is Structure Padding in C?
C 中的 Structure 填充是由 CPU architecture 处理的过程。结构填充在结构内添加一定数量的空字节,以便数据成员在内存中自然对齐。对齐要求由处理器架构而不是语言本身决定。自然,对齐要求会根据数据总线大小或特定 CPU 架构的其他架构考虑因素而更改。
Understanding Structure Padding with Examples
我们先定义结构类型如下 −
struct struct1 {
char x;
int y;
char z;
};
Example 1
让我们检查此类型变量所需的字节数 −
#include <stdio.h>
struct struct1{
char a;
char b;
int c;
};
int main(){
printf("Size: %d", sizeof(struct struct1));
return 0;
}
当你运行这段代码时,它将产生以下输出:
Size: 8
结果与预期相反。
考虑到 char 类型需要 1 个字节,而 int 类型需要 4 个字节,人们可能会认为输出应该是“1 + 1 + 4 = 6 个字节”。
然而,CPU 架构有必要更改此结构。考虑到我们正在使用具有 32 位处理器的 CPU,它一次读取 4 个字节,这意味着 1 个字等于 4 个字节。
在一次 CPU 周期中,它访问字符“a”,然后字符“b”和整数“c”的前两个字节。在第二个周期中,访问另外两个字节。
即使我们只想读取“c”,也需要两个 CPU 周期。为此,CPU 在存储“c”值所在字节之前添加两个空字节。此机制称为 padding 。
这解释了我们在上面获得的结果,即结构类型的尺寸为 8 个字节。
Example 2
让我们更改上述结构类型的成员顺序,并将“ b ”的类型和“ c ”的类型设置如下。
#include <stdio.h>
struct struct1{
char a;
int b;
char c;
};
int main(){
printf("size: %d", sizeof(struct struct1));
return 0;
}
运行代码并检查其输出:
size: 12
在前一个字的 4 个字节中,第一个字节分配给字符“a”,后跟三个空字节。
形成下一个字的下一个 4 个字节用于存储整数“b”。随后,在下一组 4 个字节中,仅一个字节用于“c”。然而,结构大小为 12。
Understanding Structure Packing with Examples
由 CPU 架构强制的填充是不可避免的,但是有办法最小化填充。可以使用以下方法来完成 −
-
Using #pragma pack(1) directive
-
Using packed attribute
Using
#pragma pack(1) 预处理器指令强制编译器在内存分配过程中忽略填充,并将结构成员端对端对齐。
让我们在之前使用的代码顶部添加此指令,并查看结果 −
#include <stdio.h>
#pragma pack(1)
struct struct1{
char a;
int b;
char c;
};
int main(){
printf("size: %d", sizeof(struct struct1));
return 0;
}
运行代码并检查其输出:
size: 6
我们可以看到,避免了结构填充并减少了内存浪费。
Using _attribute_packed
通过 GCC,我们可以使用属性指定结构和联合类型的各种特殊属性。属性包括: aligned, deprecated, packed, transparent_union, unused 和 visibility 。应用这些属性的语法是“ attribute … ”。
在此,我们将在结构类型的定义中使用 packed 属性。
#include <stdio.h>
struct __attribute__((packed)) struct1{
char a;
int b;
char c;
};
int main(){
printf("size: %d", sizeof(struct struct1));
return 0;
}
运行代码并检查其输出:
size: 6
此方法还避免了填充的影响。