鱼C论坛

 找回密码
 立即注册
查看: 2276|回复: 13

[已解决]这个结构体的对齐看了几遍都没看懂

[复制链接]
发表于 2017-4-29 20:17:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
失传的C结构体打包技艺(转)
http://bbs.fishc.com/thread-83418-1-1.html
(出处: 鱼C论坛)
尤其是后来为什么结构体内的变量,位置发生变化,就节省内存了呢? 屏幕快照 2017-04-29 下午8.06.39.png 屏幕快照 2017-04-29 下午8.07.17.png “结构体尾填充的通用法则是:编译器将会对结构体进行尾填充,直至它的跨步地址。这条法则决定了sizeof()的返回值。”这句话到底怎么理解“
@人造人 @zealstar @polt @四十二 @qq1242009750
最佳答案
2017-4-29 22:38:51
超凡天赐 发表于 2017-4-29 22:17
我的问题其实是这个,为什么结构体仅仅通过变换位置就可以节省内存?代码如下

运行结果

http://blog.csdn.net/liukun321/article/details/6974282

原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。


原则二:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-4-29 21:12:22 | 显示全部楼层

回帖奖励 +10 鱼币

#include <stdio.h>

struct foo1
{
        char *p;
        char c;
        long x;
};

int main(void)
{
        printf("char * size: %d\n", sizeof(char *));
        printf("char size: %d\n", sizeof(char));
        printf("long size: %d\n", sizeof(long));

        putchar('\n');

        printf("foo1 size: %d\n", sizeof(struct foo1));

        putchar('\n');

        struct foo1 tmp;

        printf("&tmp = 0x%X\n", &tmp);
        printf("&tmp.p = 0x%X\n", &tmp.p);
        printf("&tmp.c = 0x%X\n", &tmp.c);
        printf("&tmp.x = 0x%X\n", &tmp.x);

        return 0;
}
char * size: 4
char size: 1
long size: 4

foo1 size: 12

&tmp = 0x1DFE4C
&tmp.p = 0x1DFE4C
&tmp.c = 0x1DFE50
&tmp.x = 0x1DFE54
请按任意键继续. . .

tmp的地址是 0x1DFE4C
因为p是tmp的第一个元素,所以tmp.p的地址也是 0x1DFE4C
因为p是char *类型  ,  大小是4个字节,所以tmp.c的地址从 0x1DFE50 开始(0x1DFE4C + 4 = 0x1DFE50)
因为c是char 类型 ,大小是1个字节,所以tmp.x从0x1DFE51开始?
不,因为要对齐,所以tmp.x从 0x1DFE54开始(4字节对齐)
0x1DFE51   0x1DFE52     0x1DFE53    这3个内存空间就浪费了

你现在能明白为什么 foo1 size: 12 了吗?

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
超凡天赐 + 5 + 5 + 3 先滋瓷一下

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-29 21:15:19 | 显示全部楼层
反汇编如下

22:         struct foo1 tmp;
    23:
    24:         printf("&tmp = 0x%X\n", &tmp);
00214CDC  lea         eax,[ebp-14h]  
00214CDF  push        eax  
00214CE0  push        216CF0h  
00214CE5  call        00211352  
00214CEA  add         esp,8  
    25:         printf("&tmp.p = 0x%X\n", &tmp.p);
00214CED  lea         eax,[ebp-14h]  
00214CF0  push        eax  
00214CF1  push        216D00h  
00214CF6  call        00211352  
00214CFB  add         esp,8  
    26:         printf("&tmp.c = 0x%X\n", &tmp.c);
00214CFE  lea         eax,[ebp-10h]  
00214D01  push        eax  
00214D02  push        216E30h  
00214D07  call        00211352  
00214D0C  add         esp,8  
    27:         printf("&tmp.x = 0x%X\n", &tmp.x);
00214D0F  lea         eax,[ebp-0Ch]  
00214D12  push        eax  
00214D13  push        216E40h  
00214D18  call        00211352  
00214D1D  add         esp,8  
    28:
    29:         return 0;
00214D20  xor         eax,eax  
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-4-29 22:17:55 | 显示全部楼层
人造人 发表于 2017-4-29 21:12
tmp的地址是 0x1DFE4C
因为p是tmp的第一个元素,所以tmp.p的地址也是 0x1DFE4C
因为p是char *类 ...


我的问题其实是这个,为什么结构体仅仅通过变换位置就可以节省内存?代码如下
#include <stdio.h>
struct foo7 {
    char c;
    struct foo7 *p;
    short x;
};
struct foo8 {
    struct foo8 *p;
    short x;
    char c;
};
int main()
{
    printf("%lu\n",sizeof(struct foo7));
    printf("%lu\n",sizeof(struct foo8));
    struct foo7 f7,f8;
    printf("%p\n",&f7.c);
    printf("%p\n",&f7.p);
    printf("%p\n",&f7.x);
    printf("%p\n",&f8.p);
    printf("%p\n",&f8.x);
    printf("%p\n",&f8.c);
    return 0;
}
运行结果
24
16
0x7fff5fbff710
0x7fff5fbff718
0x7fff5fbff720
0x7fff5fbff700
0x7fff5fbff708
0x7fff5fbff6f8
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-4-29 22:18:57 | 显示全部楼层
人造人 发表于 2017-4-29 21:15
反汇编如下

22:         struct foo1 tmp;

汇编我刚刚学,现在还看不太懂。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-29 22:38:51 | 显示全部楼层    本楼为最佳答案   
超凡天赐 发表于 2017-4-29 22:17
我的问题其实是这个,为什么结构体仅仅通过变换位置就可以节省内存?代码如下

运行结果

http://blog.csdn.net/liukun321/article/details/6974282

原则一:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。


原则二:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-4-29 22:56:30 | 显示全部楼层
人造人 发表于 2017-4-29 22:38
http://blog.csdn.net/liukun321/article/details/6974282

原则一:结构体中元素是按照定义顺序一个一 ...

这篇文章解释的吼啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-29 23:05:44 | 显示全部楼层
超凡天赐 发表于 2017-4-29 22:56
这篇文章解释的吼啊

能看懂吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-4-29 23:10:30 | 显示全部楼层
人造人 发表于 2017-4-29 22:38
http://blog.csdn.net/liukun321/article/details/6974282

原则一:结构体中元素是按照定义顺序一个一 ...

甲鱼老湿的那篇文章解释的不好,太啰嗦了,而且神翻译让我逻辑混乱。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-4-29 23:14:49 | 显示全部楼层

懂了懂了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-29 23:27:51 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-30 09:05:47 | 显示全部楼层

回帖奖励 +10 鱼币

很早之前就有这样的感受,变量和变量会对齐,然后浪费一定的空间。
不过已经习以为常,没有深究的问题。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-30 12:12:21 | 显示全部楼层

回帖奖励 +10 鱼币

谢谢分享,学习了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-23 15:25:56 | 显示全部楼层

回帖奖励 +10 鱼币

对齐一定有浪费的问题,意义在于方便管理空间里的数据,可以了解一下存储结构的分页机制,这也是快速检索必须的。

我跑题了,因为来晚了,扯点别的,给楼主捧场
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-28 08:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表