问题

突然收到了一个问题:

#include<stdio.h>
#include <math.h> struct icd
{
int a; //4
char b; //1
double c; //8
}; struct cdi
{
char a;
double b;
int c;
}; int main(int argc, char const *argv[])
{
printf("%d\n", sizeof(struct icd));
printf("%d\n", sizeof(struct cdi));
}

这段代码的输出结果为:

16
24

理论上输出的结果应该是:13

好像有什么不对。

解答

查阅资料,这是编译器优化的问题。

内存对齐

现代计算机中内存空间都是按照 byte 划分的从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

为什么要内存对齐

字节对齐主要是为了提高内存的访问效率,比如intel 32为cpu,每个总线周期都是从偶地址开始读取32位的内存数据,如果数据存放地址不是从偶数开始,则可能出现需要两个总线周期才能读取到想要的数据,因此需要在内存中存放数据时进行对齐。



比如,有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。

有效对齐值(新概念)

是 #pragma pack指定值 和 结构体中最长数据类型长度 中较小的那个。有效对齐值也叫对齐系数。

每个特定平台上的编译器都有自己的默认“对齐系数”。可以通过预编译命令#pragma pack(n)

n一般取1,2,3,4,8,16

GCC编译器默认为8

对齐规则

  1. 结构体变量的首地址是有效对齐值(对齐单位)的整数倍。

  2. 结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那个的整数倍,如有需要编译器会在成员之间加上填充字节。

  3. 结构体的总大小为 有效对齐值 的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

  4. 结构体内类型相同的连续元素将在连续的空间内,和数组一样。

分析代码

struct icd
{
int a; //4
char b; //1
double c; //8
};

第一个成员为int型,所以按照4个字节对齐(第一个成员的偏移值都是0)字节对齐,说白了就是当前的偏移地址必须为n的整数倍,比如4个字节对齐,就是说当前的偏移字节数必须为4的倍数,因为第一个成员都是从offset为0开始的,所以先上4个字节来存int

第二个为char,占1个字节,前面有一个int,4个字节,此时有效对齐值为4,所以必须在填3个字节的空白字节。

最后一个为double类型的,占8个字节,此时有效对齐值为8,直接存入double

4+4+8=16

struct cdi
{
char a;
double b;
int c;
};

第一个成员为char型,所以按照1个字节对齐

然后第二个为double,占8个字节,也就是此时偏移地址,必须为8的倍数,明显前面只有1个字节,不能被8整除,所以必须在填7个字节的空白字节

最后一个为int类型的,占4个字节。

8+8+4=20

因为20不是有效对齐值的整数倍,所以在最末成员后填充4个字节。

20+4=24

最新文章

  1. Sharepoint + Office Infopart + Quick Apps for Sharepoint搭建无纸化工作平台
  2. perl 从文件里读出变量无法使用解决办法
  3. dataframe 数据统计可视化---spark scala 应用
  4. dede调用时间大全标签,不同格式!
  5. 初探async await 实现多线程处理
  6. spring8——AOP之Bean的自动代理生成器
  7. 小试牛刀 WiFi 远控 + wendu
  8. GetComputerNameEx()
  9. 基于jQuery发展历程时间轴特效代码
  10. 【DB2】Event monitor for locking
  11. C#反射类中所有字段,属性,方法
  12. Git-Credential-Manager-for-Mac-and-Linux
  13. Java对象池技术的原理及其实现
  14. XX-net 部署网络
  15. php的高性能日志系统 seaslog 的安装与使用
  16. ubuntu编译安装ruby1.9.3,从p551降级到p484
  17. 各国货币json文件
  18. 【原创】PHPstorm本地修改同步保存到远程服务器
  19. 10 阻塞队列 &amp; 生产者-消费者模式
  20. CF623D birthday 贪心 概率期望

热门文章

  1. 如何在微信小程序中使用骨架屏
  2. (一)DB、DBMS、SQL之间的关系
  3. turtle 画国旗
  4. mybatis配置和使用
  5. 【JMeter_14】JMeter逻辑控制器__交替控制器&lt;Interleave Controller&gt;
  6. rust 学习之旅一, rust编程环境相关
  7. 09.DRF-ModelSerializer
  8. Jmeter 测试接口
  9. TLS1.2协议设计原理
  10. python动态柱状图图表可视化:历年软科中国大学排行