C 结构的数据对齐
Data Alignment for C struct
CS:APP 中存在一个问题 (3.45) 关于以下结构中所有字段的字节偏移量。
struct {
int *a;
float b;
char c;
short d;
long e;
double f;
int g;
char *h;
} rec;
这是书中的答案,它给出了 c
三字节填充,d
两字节填充和 g
四字节填充。
field size offset
----- ---- ------
a 8 0
b 4 8
c 1 12
d 2 16
e 8 24
f 8 32
g 4 40
h 8 48
这是我的解决方案,只给出 c
一个字节填充和 g
四个字节填充。
field size offset
----- ---- ------
a 8 0
b 4 8
c 1 12
d 2 14
e 8 16
f 8 24
g 4 32
h 8 40
那么,我的解决方案有什么问题?似乎符合对齐规则(edit* "rule" 这里只是我自己简单的概念总结,不是完整的或笼统的),所有对象的偏移量都是对象大小的倍数。
非常感谢任何解释。
考虑到显示的对象的大小和对齐规则,即每个对象都必须对齐到其大小的倍数,那么,当结构仅使用对齐所需的填充进行布局时,偏移量应为如 Tetrau 的解决方案所示。书上解法不正确
Tetrau 解决方案中显示的偏移量实际上是由 Apple LLVM 10.0.1 和 Clang 1001.0.46.4 为 x86-64 编译产生的偏移量;下面程序的输出是:
0
8
12
14
16
24
32
40
48
struct foo {
int *a;
float b;
char c;
short d;
long e;
double f;
int g;
char *h;
} rec;
#include <stddef.h>
#include <stdio.h>
int main(void)
{
printf("%zu\n", offsetof(struct foo, a));
printf("%zu\n", offsetof(struct foo, b));
printf("%zu\n", offsetof(struct foo, c));
printf("%zu\n", offsetof(struct foo, d));
printf("%zu\n", offsetof(struct foo, e));
printf("%zu\n", offsetof(struct foo, f));
printf("%zu\n", offsetof(struct foo, g));
printf("%zu\n", offsetof(struct foo, h));
printf("%zu\n", sizeof rec);
}
备注
对象需要与其大小的倍数对齐的规则适用于本练习,但应注意这不是一般规则。一台机器可能有一些 eight-byte 对象,但只有总线和其他四个字节宽的内存访问特征,因此它最多只关心任何对象的 four-byte 对齐。或者结构成员可能是另一个结构,即大小为九个字节(例如 struct bar { char x[9]; }
),但其对齐要求不会是九个字节。
答案取决于编译器、平台和编译选项。一些例子:
作者题目怕是没看懂
CS:APP 中存在一个问题 (3.45) 关于以下结构中所有字段的字节偏移量。
struct {
int *a;
float b;
char c;
short d;
long e;
double f;
int g;
char *h;
} rec;
这是书中的答案,它给出了 c
三字节填充,d
两字节填充和 g
四字节填充。
field size offset
----- ---- ------
a 8 0
b 4 8
c 1 12
d 2 16
e 8 24
f 8 32
g 4 40
h 8 48
这是我的解决方案,只给出 c
一个字节填充和 g
四个字节填充。
field size offset
----- ---- ------
a 8 0
b 4 8
c 1 12
d 2 14
e 8 16
f 8 24
g 4 32
h 8 40
那么,我的解决方案有什么问题?似乎符合对齐规则(edit* "rule" 这里只是我自己简单的概念总结,不是完整的或笼统的),所有对象的偏移量都是对象大小的倍数。
非常感谢任何解释。
考虑到显示的对象的大小和对齐规则,即每个对象都必须对齐到其大小的倍数,那么,当结构仅使用对齐所需的填充进行布局时,偏移量应为如 Tetrau 的解决方案所示。书上解法不正确
Tetrau 解决方案中显示的偏移量实际上是由 Apple LLVM 10.0.1 和 Clang 1001.0.46.4 为 x86-64 编译产生的偏移量;下面程序的输出是:
0 8 12 14 16 24 32 40 48
struct foo {
int *a;
float b;
char c;
short d;
long e;
double f;
int g;
char *h;
} rec;
#include <stddef.h>
#include <stdio.h>
int main(void)
{
printf("%zu\n", offsetof(struct foo, a));
printf("%zu\n", offsetof(struct foo, b));
printf("%zu\n", offsetof(struct foo, c));
printf("%zu\n", offsetof(struct foo, d));
printf("%zu\n", offsetof(struct foo, e));
printf("%zu\n", offsetof(struct foo, f));
printf("%zu\n", offsetof(struct foo, g));
printf("%zu\n", offsetof(struct foo, h));
printf("%zu\n", sizeof rec);
}
备注
对象需要与其大小的倍数对齐的规则适用于本练习,但应注意这不是一般规则。一台机器可能有一些 eight-byte 对象,但只有总线和其他四个字节宽的内存访问特征,因此它最多只关心任何对象的 four-byte 对齐。或者结构成员可能是另一个结构,即大小为九个字节(例如 struct bar { char x[9]; }
),但其对齐要求不会是九个字节。
答案取决于编译器、平台和编译选项。一些例子:
作者题目怕是没看懂