问题

突然收到了一个问题:

#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

C语言中的内存对齐问题的更多相关文章

  1. C语言中的内存对齐

    最近看了好多,也编了好多C语言的浩强哥书后的题,总觉的很不爽,真的真的好怀念linux驱动的代码,好怀念那下划线,那结构体,虽然自己还很菜. 同时看了一遍陈正冲老师的C语言深度剖析,收益很多,又把唐老 ...

  2. C语言中的内存压缩技术

    C语言中的内存压缩技术 前言 在整个研究生阶段我都在参与一个LTE协议栈实现的项目,在这个项目中,我们利用一个自己编写的有限状态机框架将协议栈中每一层实现为一个内核模块.我们知道,在编写内核代码时需要 ...

  3. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  4. C++继承体系中的内存对齐

    本篇随笔讨论一个比较冷门的知识,继承结构中内存对齐的问题,如今内存越来越大也越来越便宜,大部分人都已经不再关注内存对齐的问题了.但是作为一个有追求的技术人员,实现功能永远都是最基本的要求,把代码优化到 ...

  5. C语言中的内存分配与释放

    C语言中的内存分配与释放 对C语言一直都是抱着学习的态度,很多都不懂,今天突然被问道C语言的内存分配问题,说了一些自己知道的,但感觉回答的并不完善,所以才有这篇笔记,总结一下C语言中内存分配的主要内容 ...

  6. C语言中的内存管理

    开始陆续的发一下唐老师视频的笔记吧,顺便带一些正冲哥书的的内容.不能一下都发出来,因为内容发多了自己也受不了,而且发的都是学习视频时候的一些笔记,可能会有一些问题不是很清晰. 先说一下C语言中的内存管 ...

  7. C语言中动态内存分配的本质是什么?

    摘要:C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配. 本文分享自华为云社区<[云驻共创]C语言中动态内存分配的本质>,作者: G ...

  8. windev中的内存机制及其与C语言中的内存指针相似性(一)

    windev中的内存机制,是初入windev世界必须要越过的一道高山,以下我的理解和经验未必都对,如有错误或遗漏,以后再纠正或补充!另外,以下内容,咱先谈应用,再说对机制的认识和理解. 一.新建表单, ...

  9. C语言中的内存相关问题

    内存是用来存储数据与程序的,对我们写程序来说非常重要.所以内存对程序来说几乎是本质需求.越简单的程序需要越少的内存,而越庞大越复杂的程序需要更多的内存. 注意:在嵌入式系统中有ROM和RAM两类内存, ...

随机推荐

  1. 【PHP】如何将SESSION数据存放到Redis中

    在php中,SESSION的数据默认是存放到文件中,这样性能不仅不高,而且不利于扩展.在搭建集群后,默认存放到文件中就不适用了.所以,我们一般将SESSION自定义,让SESSION中的数据存放到 数 ...

  2. Nice Jquery Validator 常用规则整理

    一些简单规则 numeric: [/^[0-9]*$/, '请填写数值'], money: [/^(?:0|[1-9]\d*)(?:\.\d{1,2})?$/, "请填写有效的金额" ...

  3. 【福利】FL Studio 20 汉化补丁包 _FL Studio 20 汉化包下载

    我这两天在网上搜索FL Studio 20汉化包,找了半天也没有找到真正的汉化包,不过好在功夫不负有心人,让我找到了一个不错的FL Studio 20汉化网站,里面提供了FL Studio 20汉化包 ...

  4. TensorFlow从0到1之XLA加速线性代数编译器(9)

    加速线性代数器(Accelerated linear algebra,XLA)是线性代数领域的专用编译器.根据 https://www.tensorflow.org/performance/xla/, ...

  5. 过来人告诉你,去工作前最好还是学学Git

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 之前遇到过很多同学私信问我:「三歪,我马上要实习 ...

  6. 【Flutter实战】六大布局组件及半圆菜单案例

    老孟导读:Flutter中布局组件有水平 / 垂直布局组件( Row 和 Column ).叠加布局组件( Stack 和 IndexedStack ).流式布局组件( Wrap )和 自定义布局组件 ...

  7. WireShark——IP协议包分析(Ping分析IP协议包)

    互联网协议 IP 是 Internet Protocol 的缩写,中文缩写为“网协”.IP 协议是位于 OSI 模型中第三层的协议,其主要目的就是使得网络间能够互联通信.前面介绍了 ARP 协议, 该 ...

  8. SpringBoot--使用Mybatis分页插件

    1.导入分页插件包和jpa包 <dependency> <groupId>org.springframework.boot</groupId> <artifa ...

  9. 前端基础:HTTP 协议详解

    参考:https://kb.cnblogs.com/page/130970/#httpmeessagestructe HTTP协议是无状态的 http协议是无状态的,同一个客户端的这次请求和上次请求是 ...

  10. ASP.NET MVC 下拉框的传值的两种方式(第二种方式未完成)

    控制器代码: public ActionResult Index() { List<SelectListItem> sli = new List<SelectListItem> ...