Linux 中结构体的内存分配问题

最近在学习Linux当中发现在使用结构体的时候会出现内存对齐问题,由于先前没有学习过关于内存分配对齐的知识,感觉很奇怪,今天终于在这里发现一篇文章讨论这个问题,有些了解了,原来是逐次对齐所致,然而如何解决,也没有看到有什么好办法,把大家的讨论请到这里!

 

刚刚试了试这样的结构

struct st
{
int i[4];
double b;
int a;
};

发现不论int i[4] 在任何位置,sizeof的结果都是32....和我以前看的不一样了.....

3q大家
 
 回复人:healer_kx(甘草{决心把CSDN改造成全国最大的文学爱好者的社区}) ( 两星(中级)) 信誉:982006-4-26 16:27:48得分:0
 
 
?

为啥我觉得是28 啊?
Top
 
 回复人:cutenoob(cute ) ( 一级(初级)) 信誉:1002006-4-26 16:34:15得分:0
 
 
?

晕...你的一颗星哪来的?
Top
 
 回复人:dch4890164(跳梁小丑) ( 三级(初级)) 信誉:1002006-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(跳梁小丑) ( 三级(初级)) 信誉:1002006-4-26 16:45:26得分:0
 
 
?

呵呵
甘草被BS了
估计郁闷了
这两天不知道这些高手怎么了
麻烦你楼主,高手也不是神
尊重点,别动不动就晕。
Top
 
 回复人:sankt(做最好的自己) ( 一星(中级)) 信誉:1102006-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(跳梁小丑) ( 三级(初级)) 信誉:1002006-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 ) ( 一级(初级)) 信誉:1002006-4-26 16:57:26得分:0
 
 
?

﹃_﹃〣 刚才说的只是开玩笑了...

~~~~~~~~~~~~~~~~~~~~~~
sankt(黄景天)

以最大的double为对齐标准,就是8个字节
======

可是在这个结构中int i[4] 不是最大的么? 默认情况下不是按照最大的来对齐么....



Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:06:39得分:0
 
 
?

Windows下sankt的分析应该是没错的,至于有人说数组名也要占一个4字节,有点笑话。
Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-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(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:09:44得分:0
 
 
?

上面图怎么乱了?
padding
|
_____v_________________________________
| |/| |/| |
| a |/| b |/padding/| c |
| |/| |/| |
+-------------------------------------+
Bytes: 1 1 2 4 8

Top
 
 回复人:healer_kx(甘草{决心把CSDN改造成全国最大的文学爱好者的社区}) ( 两星(中级)) 信誉:982006-4-26 17:20:24得分:0
 
 
?

好了,我这颗星星来了。
#pragma pack(1)的时候就是28,
#pragma pack(4)的时候也是28
有啥问题嘛?

Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:26:50得分:0
 
 
?

甘草,计较这些干嘛,错了就错了咯,搞这些编译标记出来反而显得不大度,呵呵!

Top
 
 回复人:cutenoob(cute ) ( 一级(初级)) 信誉:1002006-4-26 17:27:52得分:0
 
 
?

我的问题是为什么不按照 i[4] 来对齐...

而且好像都是按照double来对齐的...在对齐中,i[4]到底在什么位置,编译器自动为它填充了多少?
Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:36:09得分:0
 
 
?

一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的。这也就是说,char向其相邻的short对齐(当然是如果有相邻的short的话),short向相邻的int对齐,int向相邻的double进行对齐,当然这种对齐是从低地址往高地址对齐的。
一定不要以为是统一向最长的类型对齐,而是向2,4或者8这种边界依次对齐。
Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:39:21得分:0
 
 
?

因为i[4]占用两个8字节,而另外一个doube也是8字节,这样剩下的那个int因为只有4字节,所以怎么说都是这个int进行补齐,所以i[4]放到哪里都不影响结果,如果你换成i[5]就不同了!
Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 17:53:48得分:0
 
 
?

还有要说明的是,Linux下的GCC奉行的是:任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模数是2,而其它所有超过2字节的数据类型(比如long,double)都以4为对齐模数,从这里说 甘草 是没错的!
Top
 
 回复人:healer_kx(甘草{决心把CSDN改造成全国最大的文学爱好者的社区}) ( 两星(中级)) 信誉:982006-4-26 17:55:49得分:0
 
 
?

你咋老打叹号呢? 看得我一惊一吒的。。。 。。。

Top
 
 回复人:sharpdew(风刃) ( 五级(中级)) 信誉:1002006-4-26 18:05:11得分:0
 
 
?

叹号就是强调,总比打问号要好,你以为呢?
Top
 
 回复人:cutenoob(cute ) ( 一级(初级)) 信誉:1002006-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(风刃) ( 五级(中级)) 信誉:1002006-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(苦点,累点->没关系) ( 二级(初级)) 信誉:1002006-4-26 18:23:57得分:0
 
 
?

就是一个内存分配上的问题吧.数据在内存中的分配起始地址总是从偶数地址起开始分配,所以分配的空间是大于等于28.即是内存对齐(书上都有)
Top
 
 回复人:dch4890164(跳梁小丑) ( 三级(初级)) 信誉:1002006-4-26 18:30:51得分:0
 
 
?

呵呵
看来关于内存对齐还得学.

Top
 
 回复人:leolovefun() ( 一级(初级)) 信誉:1002006-4-26 23:07:44得分:0
 
 
?

为什么不是16呢,不是刚刚好吗?
----------------------------
我是新手,请高人赐教
Top
 
 回复人:navi_dx() ( 二级(初级)) 信誉:1002006-4-26 23:37:21得分:0
 
 
?

学习了,我也已为就是28
Top
 
 回复人:sdbus(sdbus) ( 一级(初级)) 信誉:992006-4-26 23:57:43得分:0
 
 
?

VC中默认8字节对齐,对于你的struct是int和double,因为8是4的倍数,所以跟位置无关了,如果你定义了一个short就有关了,
Top
 
 回复人:BaiYangSpirit(潜心学习技术) ( 二级(初级)) 信誉:1002006-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) ( 二级(初级)) 信誉:1002006-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(元创) ( 五级(中级)) 信誉:122006-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
 
 回复人:yuanchuang(元创) ( 五级(中级)) 信誉:122006-4-27 13:22:54得分:0
 
 
?

有时间应该把内存对其整理一下了……
Top
 
 回复人:ugg(逸学堂(exuetang.net)) ( 两星(中级)) 信誉:982006-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(小脖领) ( 一级(初级)) 信誉:1002006-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(小脖领) ( 一级(初级)) 信誉:1002006-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() ( 一级(初级)) 信誉:1002006-4-27 16:21:34得分:0
 
 
?

刚有人指点,
结构体的大小一定是结构体中的最大内置类型大小的倍数。
Top
 
 回复人:z331283538() ( 一级(初级)) 信誉:1002006-4-27 17:07:05得分:0
 
 
?

28
Top
 
 回复人:meicaikourou() ( 一级(初级)) 信誉:1002006-4-27 17:19:45得分:0
 
 
?

简单的规则是,在vc编译器下:内存对齐为最长类型的整数倍,不足补齐。
5*4(int) + 8(double) = 28,不是8的整数倍,补齐到32
Top
 
 回复人:cywater2000(如果) ( 二级(初级)) 信誉:1002006-4-27 18:45:43得分:0
 
 
?

mark
Top
 
 回复人:cattlenzq(吃狼的豆腐(不要给分了,散起来真麻烦!)) ( 三级(初级)) 信誉:1002006-4-27 19:09:46得分:0
 
 
?

因为32位寄存器一次最多读取的位数为32个2进制位,所以4字节对齐
Top
 
 回复人:hanyufeng(寒雨丰) ( 一级(初级)) 信誉:1002006-4-27 19:19:52得分:0
 
 
?

学习ing....
Top
 
 回复人:zqy2000zqy(ewrewrwe) ( 一级(初级)) 信誉:1002006-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
 
 回复人:zqy2000zqy(ewrewrwe) ( 一级(初级)) 信誉:1002006-4-30 11:28:33得分:0
 
 
?

linux最大照4对齐, 即使有double
Top
 
 回复人:xombat(壞牧羊人) ( 一级(初级)) 信誉:1002006-4-30 11:52:26得分:0
 
 
?

linux最大照4对齐, 即使有double
============================
study

Top
 
 回复人:ChoiceYi(简单生活) ( 一级(初级)) 信誉:1002006-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
 
 回复人:tb01412(tb) ( 二级(初级)) 信誉:1002006-4-30 19:59:28得分:0
 
 
?

linux最大照4对齐, 即使有double
============================

你好像错了!!!!

LINUX下的GCC对结构体对齐默认情况下用以下的标准:
1.保证结构体变量本身的地址一定是4的整倍数
2.保证结体中任何变量所处地址按其自身的自然对齐方式,比如:
一个结构体的一第个成员就是double型,那么GCC就一定保证这个成员所处地址一定被8整除,由于结构体本身的地址是按4字节对齐的,那么这个结构体的开始处就有4字节的空洞存在!!!
如果结构体的第一个成员是short型,第二个成员是int型,那么由于结构体本身地址是能被4整除,那么这个地址就当然可以被2整除,所以第一个成员的地址就是结构体变量的首地址,其间没有空洞,再往下看,第二个成员是int型,GCC一定要保证其被4整除,由于结构体首地址能被4整除,再加一个short型变量所占空间之后就不能再被4整除,所以GCC就会在第二个成员与第一个成员间填充两个字节的空洞,从而保证第二个成员,也就是int型的那个变量一定要能被4整除的
以此类推,再回过去看上面的回贴中的所有例子,你就明白对齐是怎么回事了,需要注意一点的是:对齐的处理与编译器密切相关,所以我不能保证这个东东能在非GCC编译器下通过
Top
 
 回复人:lei001(太极) ( 三级(初级)) 信誉:1002006-4-30 20:06:23得分:0
 
 
?

四字节对齐的,无论i[4]在什么位置,大小不会变!
试试下面的情况,应该是不一样的
struct{
short a;
int i;
short b
}Node;
Top
 
 回复人:tb01412(tb) ( 二级(初级)) 信誉:1002006-4-30 21:28:56得分:0
 
 
?

不好意思,纠正一下我上一回贴中的错误,LINUX下GCC在对double类型的成员时,其地址同样是被4整除的,而不是被8整除
Top
 
 回复人:zqy2000zqy(ewrewrwe) ( 一级(初级)) 信誉:1002006-4-30 23:44:59得分:0
 
 
?

LINUX下的GCC对结构体对齐默认情况下用以下的标准:
1.保证结构体变量本身的地址一定是4的整倍数
2.保证结体中任何变量所处地址按其自身的自然对齐方式,比如:
一个结构体的一第个成员就是double型,那么GCC就一定保证这个成员所处地址一定被8整除,由于结构体本身的地址是按4字节对齐的,那么这个结构体的开始处就有4字节的空洞存在!!!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果结构体的第一个成员是short型,第二个成员是int型,那么由于结构体本身地址是能被4整除,那么这个地址就当然可以被2整除,所以第一个成员的地址就是结构体变量的首地址,其间没有空洞,再往下看,第二个成员是int型,GCC一定要保证其被4整除,由于结构体首地址能被4整除,再加一个short型变量所占空间之后就不能再被4整除,所以GCC就会在第二个成员与第一个成员间填充两个字节的空洞,从而保证第二个成员,也就是int型的那个变量一定要能被4整除的
以此类推,再回过去看上面的回贴中的所有例子,你就明白对齐是怎么回事了,需要注意一点的是:对齐的处理与编译器密切相关,所以我不能保证这个东东能在非GCC编译器下通过
=====================================================================

struct x
{
double a;
};
你的意思 这个sizeof(struct x) 是8+4 ???
Top
 
 回复人:tb01412(tb) ( 二级(初级)) 信誉:1002006-5-1 11:23:01得分:0
 
 
?

to 楼上的:
我在上一回贴中已纠正我的错误,就是double类型变量的自然对齐方式依然是被4整除,而不是被8整除,也就是说既然结构体本身能被4整除,它的第一个成员是double型,double型的自然对齐方式同样是被4整除,所以这个成员与结构体本身所在地址之间没有空洞的!!!!!!我之前没有想到double型的自然对齐方式是被4整除,而理解成了被8整除,这是我犯的错误,不好意思!!!!

其实一种类型的自然对齐方式并不一定是这个成员本身所占内存大小,LINUX下的GCC所支持的各种类型自然对齐方式,其最大为被4整除的,比如一个结构体无论它本身占用多大空间,其自身所在地址依然是被4整除的,而不是结构体有多大,它所处的地址就以多大的字节对齐!!!这是一个误区,之所以最大以4字节对齐,是由于CPU寻址决定的,CPU的寻址就是4字节,所以你用4字节对齐与8字节对齐对于CPU来说没有任何影响,既然没有影响,那么为何还要去留下空洞呢???

除了上面我说的那个错误之外,其它的都是正确的,可以去理解一下!!!!这样就可以举一反三了!!!
Top
 
 回复人:zqy2000zqy(ewrewrwe) ( 一级(初级)) 信誉:1002006-5-1 22:44:17得分:0
 
 
?

to 楼上的。

你的意思我明白,你开始说的有些让人费解, 因为讨论的是sizeof() 这个表达式
比如struct gg
{
char a;
}
这个结构体的变量确实实际占用的4个字节,因为cpu按字寻址,
但是sizeof(struct gg)=1; !!!
Top
 
 回复人:tb01412(tb) ( 二级(初级)) 信誉:1002006-5-2 0:19:53得分:0
 
 
?

不要用sizeof(struct gg),这个不能说明问题,你需要在定义一个gg的变量后,再在其后定义另一个变量,将这两个变量的地址相减才能求出实际结果,而且你的测试一定是在VC中,GCC中是4个字节的

不能用这种方式来求结构体占用的空间,这是不准确的,不过在另一种程度上可以说得过去,因为结构体地址是被4整除,而结构体的第一个成员所在地址与结构体本身所占地址之间没有空洞存在的,而其成员又只占一个字节,所以VC编译器的sizeof语句就把它设成了一个字节,这跟编译器密切相关,你换成GCC之后就不一样了,无论这个表达示的结果如何,其内存占用空间的布局是可以预测的,只要知道了这个道理,就可以举一反三了,所以那些面试题出的sizeof之类的简直没有任何意义,不去追求本质,去追求现象有什么用呢???
之所以在VC下的sizeof设成这种规则,其目的是让人更好理解,屏蔽了细节,让人知其然不知其所以然,细想一下:什么时候会用sizeof,无非就是填充数据的时候,如果你需要动态地确定该填多少字节,比较好的方法就是先用sizeof这个表达示求出来,在
struct gg
{
char a;
}
中,写代码的人一看就知道只有一个字节被占用,所以理所当然就只填充一个字节进去,余下的工作就交给编译器去做,因为编译器会自动填充余下的三个空洞,而但是sizeof(struct gg)=1让人看起来更自然,因为其内容就只有一个字节啊,当然结果就应该是1个字节了啊,无论你将sizeof表达示的值置成1或者4,对程序结果没有任何影响,用下面的例子来说明:
struct gg test;
memset(&test,0,sizeof(struct gg));
如果sizeof(struct gg)结果是1,那么内存中接下来的三个字节就是编译器填充的固定字符,这个字符在GCC下就是0xc, 也就是说内存中第一个字节是0,接下来的三个字节是0xc,如果sizeof(struct gg)结果是4,那么内存中的四个字节都是0,说到这里,好像结果造成了明显的不同之处,但实际没有什么影响,接下来,如果调用下面一条语句:
test.a='a';
那么编译器会帮你做一个工作,你将其反汇编看一下就明白了,就是将四个字节全部取出,但会忽略掉三个字节,也就是让那三个字节形同虚设,而只取那个a所占8位的数据,并修改其数据,其余24位不变,最后再存回内存,所以无论你的sizeof(struct gg)是1或是4,对你的代码是透明的!!!!!而微软的东东一向就是以易用为原则,为了让程序员更好理解,所以就让sizeof(struct gg)等于1,而不是4,随之而来的就会给想要了解其细节的人设了一道障碍,而GCC刚好相反,处处在显示其实现细节,而不是隐藏细节

最后还想多说两句:现在很多公司的面试题都考这个内容,其实这些人出题根本不严谨,没有说是什么CPU,什么平台,什么编译器,不同的环境下其结果是不同的,而且根本就没考出重点,重点是在理解内存布局,是在编译器的处理,而不是一个表达示,这个表达示,死背都背得出来,但很少人能说出为什么!!!!!
你可以写下下面的测试代码,观测其执行结果,再回头来思考:
#include <stdio.h>
struct gg
{
char a;
}

stuct gg test;
char test_str_temp1[4];
char test_str_temp2[4];

int main(int argc,char **argv)
{
memcpy(test_str_temp1,&test,4);
test.a = 'a';
memcpy(test_str_temp2,&test,4);
printf("*******0x%x 0x%x 0x%x 0x%x *******/n",test_str_temp1[0],test_str_temp1[1],test_str_temp1[2],test_str_temp1[3]);
printf("*******0x%x 0x%x 0x%x 0x%x *******/n",test_str_temp2[0],test_str_temp2[1],test_str_temp2[2],test_str_temp2[3]);
printf("------0x%x---------/n",test.a);
return 0;
}
Top
 
 回复人:tb01412(tb) ( 二级(初级)) 信誉:1002006-5-2 1:02:28得分:0
 
 
?

用下面的程序更好说明这个问题的:
#include <stdio.h>

char test_str_temp1[4];
char test_str_temp2[4];
char test_str_temp3[4];
int main(int argc,char **argv)
{
struct gg
{
char a;
};

struct gg test;
int empty;
empty = 1;
memcpy(test_str_temp1,&test,4);
test.a = 'a';
memcpy(test_str_temp2,&test,4);
memcpy(test_str_temp3,&empty,4);
printf("*******0x%x %d %d %d *******/n",test_str_temp1[0],(int)test_str_temp1[1],(int)test_str_temp1[2],(int)test_str_temp1[3]);
printf("*******0x%x %d %d %d *******/n",test_str_temp2[0],(int)test_str_temp2[1],(int)test_str_temp2[2],(int)test_str_temp2[3]);
printf("------0x%x---------/n",test.a);
printf("*******0x%x %d %d %d *******/n",test_str_temp3[0],(int)test_str_temp3[1],(int)test_str_temp3[2],(int)test_str_temp3[3]);

return 0;
}

Top
 
 回复人:leolovefun() ( 一级(初级)) 信誉:1002006-5-2 18:40:44得分:0
 
 
?

結構的大小為結構中最長成員大小的倍數( 2(short)、4(int)、8(double) ),如不想等就自動添加 bit 湊齊,剛剛看到其他的問題回覆學到D.不知道對不對???

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值