VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

有编程疑问吗?还请到提问专区发帖提问!
搜索
查看: 379|回复: 2

[转载] C++ 中 struct/class 等内存字节对齐的问题详解

[复制链接]
51_avatar_middle
online_admins Syc 发表于 2018-3-26 01:25:38 | 显示全部楼层 |阅读模式
问题引入:

定义一个结构体的一般形式为:
  1. struct 结构体名
  2. {
  3.     //类型说明符  成员名;
  4. };
复制代码


例如有如下结构体:
  1. struct Stu
  2. {
  3.     int id;
  4.     char sex;
  5.     float hight;
  6. };
复制代码


那么一个这样的结构体变量占多大内存呢?也就是:
  1. cout<<sizeof(Stu)<<endl;
复制代码

会输出什么?

在了解字节对齐方式之前想当然的会以为:sizeof(Stu) = sizeof(int)+sizeof(char)+sizeof(float) = 9
然而事实并非如此!

字节对齐原则
在系统默认的对齐方式下:每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍,且最终占用字节数为成员类型中最大占用字节数的整数倍。
在这个例子中,id 的偏移量为 0(0=4*0),sex 的偏移量为 4(4=1*4),hight 的偏移量为 8(8=2*4),此时占用 12 字节,也同时满足 12 = 3*4,所以 sizeof(Stu) = 12

(1)出现继承关系时:
  1. struct A{
  2.     int a;
  3.     char b;
  4. };
  5. struct B:A{
  6.     char c;
  7.     int  d;
  8.     long long e;
  9. };
复制代码


基类的成员总是在派生类的前面。而且即使有字节对齐,基类对齐后派生类的成员不会占用基类填充的字节,即计算好基类所占字节数后,这些字节只能由基类拥有,不能被派生类的成员占用(即char b后面有3字节的填充,之后才有char c)在派生类中成员的分布只需满足每个变量起始字节序号为该类型所占字节数的整数倍且最终大小为占用字节数最大的类型对应的字节数的整数倍。
排列如下:
  1. /*
  2.   0   4   8   12  16      24
  3.   |   |   |   |   |       |
  4.   aaaab---c---ddddeeeeeeee
  5. */
复制代码


(2)出现关联关系时:
必须满足:
1.结构体/类与结构体/类之间不会共用自动补齐的内存,即一个结构体变量/对象对齐之后填补的内存不允许被其他变量/对象占用;
2.结构体的起始字节位置必须是该结构体中所占字节数最大的变量的字节数的整数倍;
3.最终所占字节数必须是最大所占字节数最大的变量的字节数的整数倍。

(3)出现强制对齐方式时:

当然,有时候考虑到其他特殊用途,使用 #pragma pack(n) 来设定以n字节对齐的方式(n可取2的较小次幂,即 1,2,4,8,具体取值范围以及默认值与所使用的编译器有关。笔者所测试的环境下vs/vc默认为8,gcc默认为4)。
n字节对齐就是说变量存放的起始地址的偏移量有两种情况:

第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式;
第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。

比如有以下代码:
  1. #pragma pack(push) //保存对齐状态
  2. #pragma pack(4) //设定为4字节对齐
  3. struct Test
  4. {
  5.     char c1;
  6.     double d;
  7.     int i;
  8.     char c2;
  9. };
  10. #pragma pack(pop) //恢复对齐状态
复制代码


这时候编译器就会被迫使用我们约定的字节对齐方式,即4字节对齐,因此c1占4字节,d占8字节,i占4字节,c2占4字节,共20字节;
如果我们没有设置字节对齐方式,仍然使用默认对齐的话,这里sizeof(Test) = 24。

注:以上测试效果及完整代码见附件:
C++ 中 struct/class 等内存字节对齐的问题详解 code.cpp (4.06 KB, 下载次数: 2)




上一篇:函数调用的开销
下一篇:vs2008 单文档中 VC 如何实现当鼠标移动到一个菜单上时,任务栏有相应的提示

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

32_avatar_middle
在线会员 woaihot 发表于 2018-3-27 21:43:19 | 显示全部楼层
请问为什么用tcp发送构造的结构体不用考虑结构体对其呢

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

01_avatar_middle
online_admins admin 发表于 2018-4-11 00:27:30 | 显示全部楼层
woaihot 发表于 2018-3-27 21:43
请问为什么用tcp发送构造的结构体不用考虑结构体对其呢

发送时候不用经过什么计算吧,所以没必要非得对其啊

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /1 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号 )|网站地图wx_jqr

GMT+8, 2018-11-19 22:34

Powered by Discuz! X3.4

© 2009-2018 cctry.com

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