用 u_long 填充 C 结构
Padding in a C struct with u_long
所以我在 C 中定义了一个结构:
struct example {
int ex1;
u_long ex2;
float ex3;
float ex4;
};
所以示例的所有成员的大小都是 20,但是示例的大小是 24,这意味着正在添加填充。我真正不明白的是为什么以及在哪里。
对不起,如果我的术语不正确,但我认为因为它是 4 字节干净的(即所有成员的大小 % 4 == 0 ),所以不需要添加填充。是因为我是 运行 x86 它需要 8 字节干净,还是这只是常态?
然后我真的不知道填充在哪里添加,我会假设在 u_long 附近,但我不确定。
结构通常也会在末尾进行填充,以便结构的总大小可以被具有最大对齐的成员所需的对齐整除。
在您的例子中,u_long
需要对齐 8 个字节,并且将它放在第一个成员末尾后 4 个字节处,因此它的地址位于 8 个字节的边界上。结构的总大小变为 24,因此它不需要在末尾进行任何额外的填充。
末尾填充可确保在顺序数组中布局时,第二个元素不会破坏某些成员的对齐方式。
这是一个测试,运行 在一台特定的机器上,您的结果可能会有所不同:
$ cat ul.c
#include <stdio.h>
struct example {
int ex1;
unsigned long ex2;
float ex3;
float ex4;
};
struct example ex;
int main ( void ) {
printf("Size:\t%zd\n", sizeof(ex));
printf("ex @\t%p\n", &ex);
printf("ex1 @\t%p\n", &ex.ex1);
printf("ex2 @\t%p\n", &ex.ex2);
printf("ex3 @\t%p\n", &ex.ex3);
printf("ex4 @\t%p\n", &ex.ex4);
return 0;
}
$ ./ul
Size: 24
ex @ 0x600940
ex1 @ 0x600940
ex2 @ 0x600948
ex3 @ 0x600950
ex4 @ 0x600954
此处填充在ex1和ex2之间。
I thought that since it was 4 byte clean (i.e. size of all members % 4 == 0 ) that padding wouldn't need to be added.
这不是一个安全的假设。 C 对可以向 struct
表示中添加多少填充或在何处添加几乎没有限制。它根本没有说明什么时候或为什么。这些选择取决于编译器。
Is it because I am running an x86 that it needs to be 8 byte clean, or is that just the norm?
您假设“8 字节干净”与填充有任何关系。它可能会,但同样,这是一个实施决定。
一般来说,编译器会插入填充以确保所有成员都可以对齐,以便在 struct
数组的每个元素中实现最佳访问。这可能需要在成员之间或末尾或两者之间进行填充。但这仍然是一个实施考虑因素。如果你想知道你正在使用的特定 C 实现如何解决这个问题,那么你需要查阅它的文档。
所以我在 C 中定义了一个结构:
struct example {
int ex1;
u_long ex2;
float ex3;
float ex4;
};
所以示例的所有成员的大小都是 20,但是示例的大小是 24,这意味着正在添加填充。我真正不明白的是为什么以及在哪里。
对不起,如果我的术语不正确,但我认为因为它是 4 字节干净的(即所有成员的大小 % 4 == 0 ),所以不需要添加填充。是因为我是 运行 x86 它需要 8 字节干净,还是这只是常态?
然后我真的不知道填充在哪里添加,我会假设在 u_long 附近,但我不确定。
结构通常也会在末尾进行填充,以便结构的总大小可以被具有最大对齐的成员所需的对齐整除。
在您的例子中,u_long
需要对齐 8 个字节,并且将它放在第一个成员末尾后 4 个字节处,因此它的地址位于 8 个字节的边界上。结构的总大小变为 24,因此它不需要在末尾进行任何额外的填充。
末尾填充可确保在顺序数组中布局时,第二个元素不会破坏某些成员的对齐方式。
这是一个测试,运行 在一台特定的机器上,您的结果可能会有所不同:
$ cat ul.c
#include <stdio.h>
struct example {
int ex1;
unsigned long ex2;
float ex3;
float ex4;
};
struct example ex;
int main ( void ) {
printf("Size:\t%zd\n", sizeof(ex));
printf("ex @\t%p\n", &ex);
printf("ex1 @\t%p\n", &ex.ex1);
printf("ex2 @\t%p\n", &ex.ex2);
printf("ex3 @\t%p\n", &ex.ex3);
printf("ex4 @\t%p\n", &ex.ex4);
return 0;
}
$ ./ul
Size: 24
ex @ 0x600940
ex1 @ 0x600940
ex2 @ 0x600948
ex3 @ 0x600950
ex4 @ 0x600954
此处填充在ex1和ex2之间。
I thought that since it was 4 byte clean (i.e. size of all members % 4 == 0 ) that padding wouldn't need to be added.
这不是一个安全的假设。 C 对可以向 struct
表示中添加多少填充或在何处添加几乎没有限制。它根本没有说明什么时候或为什么。这些选择取决于编译器。
Is it because I am running an x86 that it needs to be 8 byte clean, or is that just the norm?
您假设“8 字节干净”与填充有任何关系。它可能会,但同样,这是一个实施决定。
一般来说,编译器会插入填充以确保所有成员都可以对齐,以便在 struct
数组的每个元素中实现最佳访问。这可能需要在成员之间或末尾或两者之间进行填充。但这仍然是一个实施考虑因素。如果你想知道你正在使用的特定 C 实现如何解决这个问题,那么你需要查阅它的文档。