gcc 和 vc2010 对求结构体的 sizeof 会有所不同。比如下面这段程序:
[C++] 纯文本查看 复制代码 #include <stdio.h>
struct temp {
short a1;
short a2;
short a3;
}A;
struct temp1 {
short a1;
long a2;
}B;
struct temp2 {
char a1;
short a2;
}C;
struct temp3 {
char a1;
double a2;
}D;
int main()
{
printf ("%d %d %d %d\\n", sizeof(A), sizeof(B), sizeof(C), sizeof(D));
printf ("Address A: %p\\n", &A);
printf ("Address B: %p\\n", &B);
printf ("Address C: %p\\n", &C);
printf ("Address D: %p\\n", &D);
return 0;
}
使用 gcc 编译后运行输出:./sizeof
6 8 4 12
Address A: 0x804a028
Address B: 0x804a030
Address C: 0x804a038
Address D: 0x804a01c 使用 vc2010 编译后运行输出:6 8 4 16
Address A: 00F17154
Address B: 00F1714C
Address C: 00F17148
Address D: 00F17138 由两者的输出可见,VC2010 计算 struct temp3 这个结构体的大小为 16 个字节,也就是说它将第一个 a1 的变量的空间扩展为和 double 一样的 8 个字节了。
而在 gcc 的编译中,a1 只扩展了 4 个字节。
CPU 的优化规则大致这样:对于 n 字节的元素 (n = 2, 4, 8,...),它的首地址要能被 n 整除,才能获得最好的性能。设计编译器时可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。为了验证这个说法,我们将上面的代码里的结构体稍作修改:
[C++] 纯文本查看 复制代码 #include <stdio.h>
struct temp {
short a1;
short a2;
short a3;
}A;
struct temp1 {
char a1;
}B;
struct temp2 {
char a1;
short a2;
}C;
struct temp3 {
char a1;
double a2;
}D;
int main()
{
printf ("%d %d %d %d\\n", sizeof(A), sizeof(B), sizeof(C), sizeof(D));
printf ("Address A: %p\\n", &A);
printf ("Address B: %p\\n", &B);
printf ("Address C: %p\\n", &C);
printf ("Address D: %p\\n", &D);
return 0;
}
GCC 编译运行输出:6 1 4 12
Address A: 0x804a028
Address B: 0x804a02e
Address C: 0x804a030
Address D: 0x804a01c VC2010 编译运行输出:6 1 4 16
Address A: 00397138
Address B: 0039713E
Address C: 00397150
Address D: 00397140 对比两种编译器编译后的运行输出,B 结构体只有一个 char 变量,只占用 1 个字节,而两个编译器都将其扩展到 2 个字节后才安排 C 结构的首地址。
另一方面,结构体A 到 结构体B 之间的距离就 6 个字节,并没有扩展为 8 个字节后再安排 B 结构体的首地址,因为寻址 A 结构体中的元素时地址是按照 2 的倍数来,寻址 B 结构体中的元素是地址也是按照 2 的倍数来,所以就没必要进行扩展了。 |