c语言结构体嵌套 c语言结构体对齐的问题

2017/4/20 1:03:52

cat仍然存放到地址0-地址3处 a数组是地址4到地址27处 存放dog时编译器计算除下一个地址28并不能除尽double的字节数8,从地址0到地址39正好40个字节: cat 存放的位置是地址0-地址3 a数组存放的位置是地址4-地址23 dog存放的位置是地址24到地址31 这里可以看到它们都符合对齐的原则(即每个变量开始存放的地址可以除尽它们所占的字节数)!

c语言结构体嵌套 c语言结构体对齐的问题

为什么会有对齐的问题呢,30。 具体到这个问题就是可以先假设结构体变量从地址0处开始存放。

等你以后遇见了再给我提问吧,所以dog变量会被存放在地址32到地址39处这是个好问题,以保证对齐后再存放,这就解释了第二种情况了,8字节变量的存放要对齐到可以被8整除的地址上,所以是32 第二种情况是这样的,知道递增到32时可以将8除尽了,我给你解释?简单的说就是为了提高访问内存的效率。

c语言结构体嵌套 c语言结构体对齐的问题

其他变量类推就行了,这和CPU内部的机制有关,于是它要将地址进行递增:4字节变量的存放要对齐到可以被4整除的地址上,如果你想深入理解。

c语言结构体嵌套 c语言结构体对齐的问题

29,那么第一种情况就是这样的了。如果没对齐编译器就会将某个变量的存储往后推迟几个字节。对齐采用的总体原则是这样的,需要阅读 Intel 开发者手册,这时会牵扯到内部的结构体对齐的问题,31仍然不能除尽8.

c语言结构体嵌套 c语言结构体对齐的问题

其实你这个问题还有一种变种就是一个结构体里在套一个结构体。 ps追问首先谢谢,被你说中了,这其实是一个嵌套的问题,结构体里面嵌套了联合或者结构体,他的对齐是怎么样的。

c语言结构体嵌套 c语言结构体对齐的问题

typedef union {double i; int k[5]; char c;} DATE; struct data { int cat; DATE a; double dog;}; 顺便给我讲一下结构体嵌套结构体的问题,小弟不胜感激。

ps:解决后加50分。追答哦,这个问题很容易解答。 联合的本质就是各个变量共用一块儿存储空间,因此一个联合的大小就是联合里的具有最大字节数的变量了,因此 sizeof(DATE) = 20。

c语言结构体嵌套 c语言结构体对齐的问题

这就联合的大小就是int k[5]的大小(即联合的大小由int k[5]来决定)。 下面我们再来分析struct data类型的变量存储情况: 首先cat是四字节的int变量,因此占用的地址是0-3 DATE a是个联合变量,它本质上就是个 5个int变量的数组,而数组是一段连续的空间,也就是存放时从第一个元素k[0]开始顺序存放在内存中,因此现在编译器看到cat变量下一个地址是4,正好可以除尽k[1]的字节数4,于是k[0]就被存放在地址4到地址7处了,下面的数组中的元素存放依次顺序存放就可以了。

c语言结构体嵌套 c语言结构体对齐的问题

所以总起来数,联合的存放位置是地址4到地址23。

编译器发现紧挨着联合的下一个地址是24,正好可以除尽dog的字节数8,因此dog就被存放在了地址24-31处。所以sizeof(struct data) = 32.

c语言结构体嵌套 c语言结构体对齐的问题

嗯,你看看你能明白吗? 注意一下:我没给你画图,给你画图那位虽然得到的答案是正确的,可是过程错了,你不能那样理解。追问上面的联合size不是20,我得到的结果是24.。结构体中的联合,对齐方式是怎么样的,就是把联合看做什么对待?追答你用的微软的编译器吧。

c语言结构体嵌套 c语言结构体对齐的问题

我使用的gcc和clang编译器(FreeBSD下编译的),结果联合的大小都是20。我认为20是合理的,而不是24。这是由联合的存储本质决定的。

我可以给你解释为什么不同我们得到的是不同的答案(其实就这个问题我还是坚持认为20是合理的,而不是24)。C语言有个规范,比如说C99,这些规范有pdf的,你可以下载下来看看,我看过了。所有的C语言编译器的实现都必须参照这个规范,这个规范定义死了一些东西,还有一些东西没有指定,所以不同编译器产生的某些结果不一样,就是因为对于C规范中没有指定的东西,各个编译器的实现者采用了不同的处理方法。

c语言结构体嵌套 c语言结构体对齐的问题

微软的C编译器CL和GNU 的gcc,clang都有不同的地方。

追问奥,是这样啊,我在问一个问题就是结构体中,怎么确定按照那个字节对齐?追答哦,这个问题是这样的。 比如对于这样一个结构体 struct a {char var1; int var2; char var3;};它的大小就是12。

12是这样的来的。首先安排var1 在地址0处,var2在地址4-7处,var3在地址8处,这些应该都没问题吧。

但是怎么得到12而不是9呢,是因为紧挨这这个结构体的字节的地址要是这个结构体中对齐参数最大的倍数。这个例子中的最大的对齐参数就是var2的,为4.然后现在紧挨着结构体的下一个字节的地址是9,9不能除尽4,于是编译器接着递增地址,知道发现地址12为止,这样结构体就被存放到地址0-11了,所以是12。

下面还有一些复杂的问题。比如 struct a { char var1; int var2; char var3; }; struct b { int var1; struct a var2; double var3; /* char var3; */ }; 你能回答出sizeof(struct b) 是多少吗? 如果将struct b 中的第三个变量改变为char var3,而不是double var3。

那么sizeof(struct b)又变为多少了呢? 如果你能回答对我提出的问题才说明你真正理解了内存对齐的概念。更多追问本回答由提问者推荐评论