struct 间的字节对齐,让我惊讶

cxjddd 2003-12-14 02:44:22
问题的源来:
对这样的 struct:
struct X
{
short s;
int i;
long l;
};
在现在的 PC 中,sizeof (X) 应该是 12,那为什么在 8 字节对齐不是 16 呢?
进一步,我想到了 X 与 X 之间会是什么样子呢?

问题:
写了个检验的程序:
struct A
{
char a;
};
struct C
{
char a, b, c;
};
在 Dev-C++ 4.9.8.0(也就是 GCC 3.2)里,sizeof (A)==1,sizeof (C)==3。
我猜测,对:
A a1, a2; // 注:都在 main () 里
C c1, c2;
a1、a2,c1、c2 间的地址会差多少呢?本来我想,a1、a2 应该是差 1;而 c1、c2 应该是差 4 吧。结果在 Dev-C++ 里,a1 与 a2 是只相关 1,但 c1 与 c2 却相差了 16!!

于是我就扩大测试的范围,从 A 一直到 E:
#include <iostream>
#include <cstdlib>
using namespace std;

struct A
{
char a;
};

struct B
{
char a, b;
};

struct C
{
char a, b, c;
};

struct D
{
char a, b, c, d;
};

struct E
{
char a, b, c, d, e;
};

int
main ()
{
A a1, a2;
B b1, b2;
C c1, c2;
D d1, d2;
E e1, e2;
cout << sizeof (A) << endl;
cout << sizeof (B) << endl;
cout << sizeof (C) << endl;
cout << sizeof (D) << endl;
cout << sizeof (E) << endl;
cout << &a1 << " " << &a2 << endl;
cout << &b1 << " " << &b2 << endl;
cout << &c1 << " " << &c2 << endl;
cout << &d1 << " " << &d2 << endl;
cout << &e1 << " " << &e2 << endl;
system ("Pause");
return 0;
}

在 Dev-C++ 下的结果:
1
2
3
4
5
0x22ff67 0x22ff66
0x22ff64 0x22ff62
0x22ff48 0x22ff38
0x22ff34 0x22ff30
0x22ff18 0x22ff08

在 BCC 5.5 下的结果:
1
2
3
4
5
0012FF8B 0012FF8A
0012FF64 0012FF5E
0012FF55 0012FF4C
0012FF48 0012FF44
0012FF3C 0012FF34

在 VC6 下的结果:(命令行下编译,我没有打开任何开关)
1
2
3
4
5
0012FF60 0012FF54
0012FF50 0012FF7C
0012FF78 0012FF74
0012FF70 0012FF6C
0012FF64 0012FF58

GCC 3.2 的结果还好,只是空闲的多点;而 BCC 5.5 的结果让我看不懂了;最奇怪的是 VC6 的布局连次序都是乱的。

看来这个问题,对不同的编译器(和不同的设置)来说,差别太大了。

对于结果,我不知道分析了:(

还有如 A a[2]; B b[2]; 这样用数组又会有什么不同呢?
而 struct 内部也用 struct E { char e[5]; }; 也会不会有变呢?

困啊!睡觉去!
...全文
48 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
glacierrr 2003-12-17
  • 打赏
  • 举报
回复
有意思
smalltalk 2003-12-17
  • 打赏
  • 举报
回复
这样的分析是没有任何意义的。C/C++从来没有规定如何实现,从来没有过内存应该如何布局的标准,当然各个编译器可以自由地实现。各个编译器自然不会一样,这有什么好比的。我建议大家还是应该关注语言的功能和用途,而不是想自己搞出个编译器来。
cxjddd 2003-12-17
  • 打赏
  • 举报
回复
程序中,C、E 等大概地表示了实际使用的字节的个数。
#include <iostream>
#include <cstdlib>
using namespace std;

//#pragma pack (8)

struct C
{
char a[3];
};

struct E
{
char a[5];
};

struct F
{
char a[6];
};

struct C2
{
short a;
char b;
};

struct E2
{
int a;
char b;
};

struct F2
{
int a;
short b;
};

struct F3
{
short a[3];
};

struct J
{
double a;
short b;
};

struct L
{
long double a;
};

struct N
{
long double a;
short b;
};

struct P
{
long double a;
int b;
};

struct X
{
long double a[2];
};

int
main ()
{
C c1, c2;
E e1, e2;
F f1, f2;
cout << "(C) " << sizeof (C) << endl;
cout << "(E) " << sizeof (E) << endl;
cout << "(F) " << sizeof (F) << endl;
cout << &c1 << " " << &c2 << endl;
cout << &e1 << " " << &e2 << endl;
cout << &f1 << " " << &f2 << endl;

C c[4];
cout << c << " " << c+1 << " " << c+2 << " " << c+3 << endl;

cout << "(C2) " << sizeof (C2) << endl;
C2 c21, c22;
cout << &c21 << " " << &c22 << endl;
C2 c2a[4];
cout << c2a << " " << c2a+1 << " " << c2a+2 << " " << c2a+3 << endl;

cout << "(E2) " << sizeof (E2) << endl;
E2 e21, e22;
cout << &e21 << " " << &e22 << endl;
E2 e2a[4];
cout << e2a << " " << e2a+1 << " " << e2a+2 << " " << e2a+3 << endl;

cout << "(F2) " << sizeof (F2) << endl;
F2 f21, f22;
cout << &f21 << " " << &f22 << endl;
F2 f2a[4];
cout << f2a << " " << f2a+1 << " " << f2a+2 << " " << f2a+3 << endl;

cout << "(F3) " << sizeof (F3) << endl;
F3 f31, f32;
cout << &f31 << " " << &f32 << endl;
F3 f3a[4];
cout << f3a << " " << f3a+1 << " " << f3a+2 << " " << f3a+3 << endl;

cout << "(J) " << sizeof (J) << endl;
J j1, j2;
cout << &j1 << " " << &j2 << endl;
J j[4];
cout << j << " " << j+1 << " " << j+2 << " " << j+3 << endl;

cout << "(L) " << sizeof (L) << endl;
L l1, l2;
cout << &l1 << " " << &l2 << endl;
L la[4];
cout << la << " " << la+1 << " " << la+2 << " " << la+3 << endl;

cout << "(N) " << sizeof (N) << endl;
cout << "(P) " << sizeof (P) << endl;
cout << "(X) " << sizeof (X) << endl;
system ("Pause");
return 0;
}
cxjddd 2003-12-17
  • 打赏
  • 举报
回复
虽然像 S s1, s2; 这样的排列,可能 s1 与 s2 是不相邻的,但在数组里, a[0] 与 a[1] 是绝对相邻的,也就是 abs(long(a+1) - long(a+0)) ≡ sizeof (S)。
  对 malloc 来说,与数组是完全一样的。
cxjddd 2003-12-17
  • 打赏
  • 举报
回复
觉得各种编译器都有一个共同点,尽可能让一个内部类型的访问最简化,表现出来,就像是向最大的靠拢,保证最大的成员不被截断。
  也许可以用公式表示:sizeof (S) = n * W, W = min (pack, max (sizeof(Si)) )
其中,min (pack, sizeof(Si)) 表示取“系统对齐大小”与 “S的成员中最大者”中较小的一个。

比如:
struct { short a, char b; }; 就是向 short 靠拢,这样 sizeof 大小就是 4。

一个 struct 的大小应该是保证 struct 内的成员可以尽量优化的被访问到,包括在数组内。
mpcdd 2003-12-16
  • 打赏
  • 举报
回复
是机器字对齐,只要用来加快存取速度,不同的编译器有不同的实现.
cxjddd 2003-12-15
  • 打赏
  • 举报
回复
想不通数组和 malloc 的时候会怎样
yonyon 2003-12-15
  • 打赏
  • 举报
回复
gz
nirvana_li 2003-12-15
  • 打赏
  • 举报
回复
不同的编译器在实现优化上的细节是不一样的,楼主够细心..感谢....
chenzhangf 2003-12-15
  • 打赏
  • 举报
回复
应该是定义结构字段少用char这种一个字节的类型。
chenzhangf 2003-12-15
  • 打赏
  • 举报
回复
楼上的强,通常为#pragma pack(2)
zming 2003-12-15
  • 打赏
  • 举报
回复
编译器自动优化处理。不同的编译器的自动优化处理不同。

上述问题涉及struct与union的字节对齐方式,不同的编译器缺省对齐方式不同。(可通过编译参数来调整对齐方式的设置)

但从可移植性考虑,通常使用预编译命令来指示。

#pragma pack(n) // n的取值范围为:1, 2, 4, 8, 16

预处理命令#pragma pack(n)指示编译器使用程序预定义的对齐方式,而不是使用编译器缺省的对齐方式。

例1:

#include "stdio.h"
#pragma pack(1) // 或 #pragma pack(2)

struct X
{
short s;
int i;
long l;
};

main()
{
fprintf(stdout, "%d\n", sizeof(X));
}

输出为: 10

例2:

#include "stdio.h"
#pragma pack(4) // 或 #pragma pack(8) 或 #pragma pack(16)

struct X
{
short s;
int i;
long l;
};

main()
{
fprintf(stdout, "%d\n", sizeof(X));
}

输出为: 12

layman2008 2003-12-14
  • 打赏
  • 举报
回复
多谢,楼主,学到了!
19830711 2003-12-14
  • 打赏
  • 举报
回复
楼主果然心细呀
codelover 2003-12-14
  • 打赏
  • 举报
回复
高手,细心的程序员,向你致敬。
cpsoft 2003-12-14
  • 打赏
  • 举报
回复
这涉及到编译器的优化问题了!

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧