最近在学习Linux当中发现在使用结构体的时候会出现内存对齐问题,由于先前没有学习过关于内存分配对齐的知识,感觉很奇怪,今天终于在这里发现一篇文章讨论这个问题,有些了解了,原来是逐次对齐所致,然而如何解决,也没有看到有什么好办法,把大家的讨论请到这里!
刚刚试了试这样的结构
struct st { int i[4]; double b; int a; };
发现不论int i[4] 在任何位置,sizeof的结果都是32....和我以前看的不一样了.....
3q大家
|
|
|
|
回复人:dch4890164(跳梁小丑) ( ) 信誉:100 |
2006-4-26 16:43:22 |
得分:0 |
|
|
? |
这个估计是和编译器有关 有数组和没有数组不一样 我刚才拿 struct st { int i[4]; double b; int a; }; struct a { int i; int j; double b; }; st的确是32但是a是16说明有数组和没有数组存在区别,这有可能和数组的存储方式有关 要么数组是以存储一个地址 数组名4个 另外加上一个存储的元素4*4所以最后得32 不知道有人又更好的解释吗?
|
|
Top |
|
|
回复人:dch4890164(跳梁小丑) ( ) 信誉:100 |
2006-4-26 16:45:26 |
得分:0 |
|
|
? |
呵呵 甘草被BS了 估计郁闷了 这两天不知道这些高手怎么了 麻烦你楼主,高手也不是神 尊重点,别动不动就晕。
|
|
Top |
|
|
回复人:sankt(做最好的自己) ( ) 信誉:110 |
2006-4-26 16:48:56 |
得分:0 |
|
|
? |
struct st { int i[4]; double b; int a; };
发现不论int i[4] 在任何位置,sizeof的结果都是32....和我以前看的不一样了.....
//=========== 以最大的double为对齐标准,就是8个字节 int i[4]; //16 double b; //8 int a; //8
所以 sizeof(st) == 32
|
|
Top |
|
|
回复人:dch4890164(跳梁小丑) ( ) 信誉:100 |
2006-4-26 16:54:32 |
得分:0 |
|
|
? |
#pragma pack([ 4]); 楼上的改成这个结果还是一样 而且为什么 struct st { int i[4]; double b; int a; }; struct a { int i; int j; double b; }; 一个是32 一个是16如果不强行对齐的话。 呵呵
|
|
Top |
|
|
回复人:cutenoob(cute ) ( ) 信誉:100 |
2006-4-26 16:57:26 |
得分:0 |
|
|
? |
﹃_﹃〣 刚才说的只是开玩笑了...
~~~~~~~~~~~~~~~~~~~~~~ sankt(黄景天)
以最大的double为对齐标准,就是8个字节 ======
可是在这个结构中int i[4] 不是最大的么? 默认情况下不是按照最大的来对齐么....
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:06:39 |
得分:0 |
|
|
? |
Windows下sankt的分析应该是没错的,至于有人说数组名也要占一个4字节,有点笑话。
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:08:33 |
得分:0 |
|
|
? |
不是按照最大的来对齐,而是从头开始一步一步对齐,看看下面这个: typedef struct ms3 { char a; short b; double c; } MS3;
内存正确的布局图如下:
padding | _____v_________________________________ | |/| |/////////| | | a |/| b |/padding/| c | | |/| |/////////| | +-------------------------------------+ Bytes: 1 1 2 4 8
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:09:44 |
得分:0 |
|
|
? |
上面图怎么乱了? padding | _____v_________________________________ | |/| |/////////| | | a |/| b |/padding/| c | | |/| |/////////| | +-------------------------------------+ Bytes: 1 1 2 4 8
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:26:50 |
得分:0 |
|
|
? |
甘草,计较这些干嘛,错了就错了咯,搞这些编译标记出来反而显得不大度,呵呵!
|
|
Top |
|
|
回复人:cutenoob(cute ) ( ) 信誉:100 |
2006-4-26 17:27:52 |
得分:0 |
|
|
? |
我的问题是为什么不按照 i[4] 来对齐...
而且好像都是按照double来对齐的...在对齐中,i[4]到底在什么位置,编译器自动为它填充了多少?
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:36:09 |
得分:0 |
|
|
? |
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的。这也就是说,char向其相邻的short对齐(当然是如果有相邻的short的话),short向相邻的int对齐,int向相邻的double进行对齐,当然这种对齐是从低地址往高地址对齐的。 一定不要以为是统一向最长的类型对齐,而是向2,4或者8这种边界依次对齐。
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:39:21 |
得分:0 |
|
|
? |
因为i[4]占用两个8字节,而另外一个doube也是8字节,这样剩下的那个int因为只有4字节,所以怎么说都是这个int进行补齐,所以i[4]放到哪里都不影响结果,如果你换成i[5]就不同了!
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 17:53:48 |
得分:0 |
|
|
? |
还有要说明的是,Linux下的GCC奉行的是:任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模数是2,而其它所有超过2字节的数据类型(比如long,double)都以4为对齐模数,从这里说 甘草 是没错的!
|
|
Top |
|
|
回复人:cutenoob(cute ) ( ) 信誉:100 |
2006-4-26 18:06:35 |
得分:0 |
|
|
? |
sharpdew(风刃)谢谢了 ~~~~~~~
可否把我下面这个问题来讲下?
1 struct A { char c; string str; }; ~~~~~~~ struct A { short int s; string str; }; ~~~~~~~ struct A { int i; string str; }; ~~~~~~~
以上的三个结构的sizeof都是20.....
|
|
Top |
|
|
回复人:sharpdew(风刃) ( ) 信誉:100 |
2006-4-26 18:22:59 |
得分:0 |
|
|
? |
是str占用了16个字节,其他的char,short,int向4这个单位对其呀,简单的规则就是windows vs下是小于4向4对齐,大于4向8对齐,只是基本类型哦,如果是复杂对象的话展开其成员变量进行类似对其;linux下的gcc规定都向4对齐。 你最好再加一个: struct A { double i; string str; }; 这样就需要重新对齐了,编译系统具体的对齐方式相当于把string的成员展开到这个结构中进行从低位到高位的对齐。
|
|
Top |
|
|
回复人:ENOUGH_XU(苦点,累点->没关系) ( ) 信誉:100 |
2006-4-26 18:23:57 |
得分:0 |
|
|
? |
就是一个内存分配上的问题吧.数据在内存中的分配起始地址总是从偶数地址起开始分配,所以分配的空间是大于等于28.即是内存对齐(书上都有)
|
|
Top |
|
|
回复人:leolovefun() ( ) 信誉:100 |
2006-4-26 23:07:44 |
得分:0 |
|
|
? |
为什么不是16呢,不是刚刚好吗? ---------------------------- 我是新手,请高人赐教
|
|
Top |
|
|
回复人:sdbus(sdbus) ( ) 信誉:99 |
2006-4-26 23:57:43 |
得分:0 |
|
|
? |
VC中默认8字节对齐,对于你的struct是int和double,因为8是4的倍数,所以跟位置无关了,如果你定义了一个short就有关了,
|
|
Top |
|
|
回复人:BaiYangSpirit(潜心学习技术) ( ) 信誉:100 |
2006-4-27 11:20:43 |
得分:0 |
|
|
? |
VC中 sizeof(int) 是4 sizeof(double)是8; 在 int i[4],应该占16,刚好是两个sizeof(double),int i[4]和double b对齐了,所以不论你如何改变位置,也看不到你期望的结果 而另外一个int a;也占了8B。 =============== 改成这样: struct st { double b; int i[3]; int a; }; 然后将int i[3];挪来挪去,就看到结果了
|
|
Top |
|
|
回复人:gjianpro(#ifndef _DEBUG) ( ) 信誉:100 |
2006-4-27 12:52:21 |
得分:0 |
|
|
? |
eg: struct B { char b; int a; short c; }; 假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12;
|
|
Top |
|
|
回复人:yuanchuang(元创) ( ) 信誉:12 |
2006-4-27 13:13:52 |
得分:0 |
|
|
? |
struct st { int i[5]; double b; int a; };//结果是40; struct st { int i[6]; double b; int a; };//结果也是40 struct st { int i[4]; double b; int a; char c; };结果32; struct st { int i[5]; int a; double b; };//结果是32 ……
上面的内容我随手写的,没有测试。 内存对其有很多细节的,包括下一个变量从什么位置开始,包括整个结构的内存补齐。 一言两语很难讲清
|
|
Top |
|
|
回复人:ugg(逸学堂(exuetang.net)) ( ) 信誉:98 |
2006-4-27 13:39:47 |
得分:0 |
|
|
? |
struct st { int i[4]; // 16 double b; // 注意这时16字节是8的倍数,所以这里不用对齐,8 int a; // 前面是24是4倍数,所以是4 }; // 现在总共是28,因为28不是结构内,最大字节数8的倍数,调整为8的倍数即32。
再看下面 struct st { int i[5]; // 20 double b; // 因为20不是8的倍数,所以此时要补齐4个字节。空间大小为24+8 int a; // 32是4的倍数,大小为36 };// 结构调整,为40
以上说到的倍数都是这整数倍。
|
|
Top |
|
|
回复人:wjlsmail(小脖领) ( ) 信誉:100 |
2006-4-27 14:14:53 |
得分:0 |
|
|
? |
struct st { int i[4]; // 4, 0 % 4 = 0, 4 * 5---- 这里是4个整型连续分布。这里可能涉及整个结构的平移 double b; // 8, 16 % 8 = 0, 8 int a; // 4, 24 % 4 = 0, 4 }; // max(4, 8, 4) = 8, (16 + 8 + 4) % 8 != 0 因此整个结构需要补齐,在后边补齐, 32
struct st { int i[5]; // 4, offset + 4 × 5 double b; // 8, 20 % 8 != 0, 因此向前补 4 个字节从 24开始分配 b 的内存, 8 int a; // 4, (20 + 4 + 8) % 4 = 0, 4 }; // max(4, 8, 4) = 8, (20 + 4 + 8 + 4) % 8 != 0, 整个结构需要补齐,在后边补齐, 40
|
|
Top |
|
|
回复人:wjlsmail(小脖领) ( ) 信誉:100 |
2006-4-27 14:25:06 |
得分:0 |
|
|
? |
// 两个 32 是不一样的
struct st1 { int a; // 4 double b; // 4 + 8 int i[4]; // 4 * 4 }; // max(4, 8, 4) = 8, 32 % 8 = 0, 32
struct st2 { int i[4]; // 4 * 4 double b; // 8, 16 % 8 = 0, 8 int a; // 4, 24 % 4 = 0, 4 }; // max(4, 8, 4) = 8, 28 % 8 != 0, 后面补4个字节, 32
|
|
Top |
|
|
回复人:iawfnusr() ( ) 信誉:100 |
2006-4-27 16:21:34 |
得分:0 |
|
|
? |
刚有人指点, 结构体的大小一定是结构体中的最大内置类型大小的倍数。
|
|
Top |
|
|
回复人:meicaikourou() ( ) 信誉:100 |
2006-4-27 17:19:45 |
得分:0 |
|
|
? |
简单的规则是,在vc编译器下:内存对齐为最长类型的整数倍,不足补齐。 5*4(int) + 8(double) = 28,不是8的整数倍,补齐到32
|
|
Top |
|
|
回复人:zqy2000zqy(ewrewrwe) ( ) 信誉:100 |
2006-4-30 11:27:37 |
得分:0 |
|
|
? |
这个和编译器有关 linux下就不同 struct st { int i[5]; double b; int a; };//结果是32; struct st { int i[6]; double b; int a; };//结果也是36 struct st { int i[4]; double b; int a; char c; };结果32; struct st { int i[5]; int a; double b; };//结果是32
|
|
Top |
|
|
回复人:xombat(壞牧羊人) ( ) 信誉:100 |
2006-4-30 11:52:26 |
得分:0 |
|
|
? |
linux最大照4对齐, 即使有double ============================ study
|
|
Top |
|
|
回复人:ChoiceYi(简单生活) ( ) 信誉:100 |
2006-4-30 14:35:53 |
得分:0 |
|
|
? |
meicaikourou() 简单的规则是,在vc编译器下:内存对齐为最长类型的整数倍,不足补齐。 5*4(int) + 8(double) = 28,不是8的整数倍,补齐到32 加上 gjianpro(#ifndef DEBUG) ( ) eg: struct B { char b; int a; short c; }; 假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(struct B)=12; zqy2000zqy(ewrewrwe) linux最大照4对齐, 即使有double
综合这几个答案应该是对这个问题有清晰的答案了
|
|
Top<
|