为了账号安全,请及时绑定邮箱和手机立即绑定

如下内容,为什么多了个char就差那么多,这个怎么解释呢?

如下内容,为什么多了个char就差那么多,这个怎么解释呢?

C++
www说 2022-05-13 11:11:54
#include"iostream.h"int main(){struct date{long *a;long *fd;struct date *next;double b;}abc;cout << sizeof(abc) << endl;}// 得到结果为:24#include"iostream.h"int main(){struct date{long *a;long *fd;struct date *next;double b;char c;}abc;cout << sizeof(abc) << endl;}// 得到结果为 32
查看完整描述

3 回答

?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

这是字节对齐,每个编译器都有默认的行为。一般默认情况下是使用最大类型的大小去对齐。对齐的目的就是便于寻址,加速程序运行。一般情况下,在设计大型的系统时,都会很严格的去设计这些数据结构的,不是随便的定义几个变量,比如大规模集成电路的软件里,有很多种类型,每个类型都有成万上亿个的对象,数据结构设计的好坏会影响到内存的使用,两者差别会有几个G,甚至上百G的。不过一般设计的时候总是有些规则的,要不把大的都放在前面,小的都放在后面,要不把小的都放在前面,大的放在后面(我更偏向于前者)

当然如果你想根据实际的大小去运行,也可以,在你的程序前加上一句:

#pramga pack(1)

这样会得到你意料之中的答案,不过这样不推荐使用,因为会影响你程序的运行效率。

一般是按照你的机构里的最大的基本类型去对齐的(因为可以修改的,根据#pramga pack(x) x是你的对齐大小 )。

对于你的程序总,32为系统里,double是最大的,是8. 如果是64位系统里,都是8. 结果又会不同的。

long *a; //32位是4, 64位是8
long *fd; //32位是4, 64位是8
//在32位系统里这两个形成8, 不需要补充对齐字节
//在64位系统里两个都不需要补充字节
//所以32位, 上面两个加起来是8, 64位是16
struct date *next; //32位是4, 64位是8
//32位里,下面double是8,不能与这个4组成8个字节,因此需要补充是个4个字节来对齐到8
//64位里,指针是8,不需要补充字节来对齐
double b; // 8

所以加起来就是
32位系统: (4+4) + (4 + 4(这是补充来的)) + 8 = 24
64位系统: 8 + 8 + 8 + 8 = 32

如果你在程序前加上 #pragma pack(1)
32位: 4 + 4 + 4 + 8 = 20
64位: 8 + 8 + 8 + 8 = 32

对于你后一个,同样,最大类型是8

long *a; //32位是4, 64位是8
long *fd; //32位是4, 64位是8
//上面两个已经对齐
struct date *next; //32位是4, 64位是8
//道理一样,需要补4个字节来对齐
double b; // 8
char c; // 1, 需要补7个字节来对齐

32位: (4 + 4) + (4 + 4(补来的)) + 8 + (1 + 7(补来的)) = 32
64位: 8 + 8 + 8 + 8 + (1 + 7(补来的)) = 40

如果在你的程序前加上 #pragma pack(4) 按照4个字节来对齐, 结果又不一样的
32位: 4 + 4 + 4 + 8 + (1 + 3(补来的)) = 24
64位: 8 + 8 + 8 + 8 + (1 + 3(补来的)) = 36
如果在你的程序前加上 #pragma pack(1) 按照1个字节来对齐, 这就是实际大小
32位: 4 + 4 + 4 + 8 + 1 = 21
64位: 8 + 8 + 8 + 8 + 1 = 33

但是如果你要把一个struct date *next;移个位置结果又不不一样

long *a; //32位是4, 64位是8
long *fd; //32位是4, 64位是8
//上面两个已经对齐
double b; // 8
struct date *next; //32位是4, 64位是8
//道理一样,需要补4个字节来对齐,但是下面还有1个字节,加起来不超过8
char c; // 1, 加上上面的4是5,因此只需要补3个字节就可以达到8

这样大小又变了:
32位: (4 + 4) + 8 + ( 4 + 1 + 3(补来的)) = 24
64位: 8 + 8 + 8 + (4 + 1 + 3(补来的)) = 32

知道这个原理就能很好理解我在前面说的设计差别会带来使用内存的差别了。 其实最终就是看编译器会用多少字节来补充对齐。



查看完整回答
反对 回复 2022-05-16
?
萧十郎

TA贡献1815条经验 获得超13个赞

编译器会对结构和类的成员进行某种“对齐”操作
最大的是double,8个字节
其他的成员会按照8个字节来补齐
2个long*刚好是8个字节,1个struct date*是4个字节,后面补4个字节构成8个字节,然后再加double的8个字节,一共是24个字节

第2个例子里,上面24个字节以后,还有一个char,1个字节,补7个字节构成8个字节,所以加起来一共是32字节
如果你把char c放在double b的前面,那么还是24个字节,因为strct date*和char一共5个字节,补3个字节就构成8个字节了



查看完整回答
反对 回复 2022-05-16
?
跃然一笑

TA贡献1826条经验 获得超6个赞

字节对齐,基本原理是,在计算结构体占用字节时,以内部成员最长字节为标准,其它小于最长字节以它为标准补足空字节,达到整齐的效果(真正作用是为了最短时间寻址)

从下面的排列顺序来看
struct date
{
long *a;
long *fd;
struct date *next;
double b;
char c;
}

最长字节长度是 8 字节,那么形象的字节排列方式是这样的
44
8
44(第2个4便是补齐的空字节)
17(同样这个7也是补齐的空字节)

这就又有问题了,为什么不是 4+1+3(补3个字节),而且这样还节省内存
你是对的,不过编译器一般不会这么小器
因为补齐的字节最小单位是2,而且一般是2的倍数,所以补3个字节对编译器来说是破天荒,不采用。
于是就有上面补齐效果。

当然,你可以强制要求最小单位是1,这样就可以有多少省多少了~

对了,#pragma pack(2)// 这条命令就是强制措施了


查看完整回答
反对 回复 2022-05-16
  • 3 回答
  • 0 关注
  • 166 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号