结构体的内存对齐&共用体的大小端问题

结构体在分配内存是需要遵循内存对齐的规则,比如下面的例子中,占字节数最大的数据类型是int,占4个字节.那么该结构体在分配内存的时候,所分得的总字节数就必须是4的倍数.

我用开房的例子来讲解,加入a,b,c每个人住宿的时候对房间面积的最小要求是1平米,4平米,1平米.如果能保证这个空间大小,他们是愿意挤一个房间的,但是房间的大小规格是一样的,它总是刚好能满足需求最大的那个人,即每个房间4平米.注意分房间是必须是按照顺序来分,具体过程可以这么来理解:

1,先开第一个房,让a住进去.
2,因为b没有办法塞到第一个房间里,所以需要再开第二间房.
3,由于b刚好住满第二间房,所以c只能再开一间房单独住.
**所以最终需要开3间房,一共是12平米.有人会问,为什么a,c不去挤一间房呢.这么跟你解释,他们分配的顺序不连续,想挤在一起都没有机会.

typedef struct Node
    {
        char    a;
        int     b;
        char    c;
    }Node;
    printf("%d", sizeof(Node));  //12

知道了内存分配的规则,我们只需要做一个小小的调整,就可以立马节约4个字节的空间出来,就想下面这样:

typedef struct Node
    {
        char    a;
        char    c;
        int     b;
    }Node;
    printf("%d", sizeof(Node));  //8

再来说一下计算机内存大小端的问题:
首先解释一下什么是大端和小端,我们都知道数据在计算机内存当中是以二进制数的形式进行存储的,这里我用数值类型的数据举例说明,比如现在有一个十六进制数:
int a = 0x12345678;
对于这样一个正数a,它的原码反码补码是一样的,计算机存储时存的是补码.对于a来说,它的高位到低位是对应的顺序是从左往右.同时我们知道计算机的最小存储单元是字节,一个字节占八个二进制位,每一个十六进制的数都可以转换为4位的二进制数,那么对于a这样的一个八位的十六进制数,在存储时,是两两一组存储于一个字节当中.然而两两一组存储时也会有一个先后顺序,这就是我们要讨论的大小端的区别,
所谓大端模式,就是高位数据部分存在低地址,而低位数据部分存储于高地址,所以如果是大端模式的计算机,我们在内存中查看a的存储结构时,看到的是:12 23 56 78,这种存储的方式比较符合我们常规的理解,有点类似于我们在字符串在内存中的存储形式.

而小端模式,刚好相反,高位数据部分存在高地址,而低位数据部分存储于低地址,这种存储模式下,我们看到的是:78 56 23 12

下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址单元
x1=((char*)&x)[1]; //高地址单元
若x0=0x11,则是大端; 若x0=0x22,则是小端......

对于共用体,我们知道是多个数据共享一段内存区域,即他们的存储地址是一样的.同一时间该存储区域只会存放一个元素的数据,所以在给共用体的元素赋值时,实际上会发生相互覆盖的情况,当我们读取一个被覆盖掉的值时会得到什么结果,就取决于计算机的大小端模式了.
比如:

typedef union NODE
    {
        char    a;
        short   b;
        int     c;
    }NODE;
    NODE n;
    n.a = 'a';
    n.b = 0x1261;
    n.c = 0x11111261;a
    printf("%c %x %x", n.a, n.b, n.c);  //a 1241 11111241

上面这种情况下,我们看似成功的将三个数据同时保存到了一块存储区域当中了,但实际上这只是一种巧合.因为我的计算机是小端模式:
第一次给a赋值’a’,即将ascii码97(即十六进制的61)存入内存中共用体n的首地址.由于计算机再给n分配内存时只会按照它占字节数最多的成员类型分配,所以n的中存储空间大小时4个字节,此时该存储区域可以表示为:
61 – – –
紧接着我们给b赋值,由于b占两个字节,而计算机又是小端模式,发生覆盖后的内存区域将刷新为以下形式:
61 12 – –
细心的朋友应该已经发现,这样覆盖的结果刚好可以保证我们第一次存进去的数据不用发生改变,再给c赋值时,刷新后可以表示为:
61 12 11 11
所以我们的三个元素的数据可以相安无事的共处,

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值