字节对齐看这篇就够了(内存对齐)
前言
大家好,我是小昭,因为在不同硬件平台数据传输时,遇到关于字节对齐的问题,索性就做了总结,以下是我对字节对齐的理解和小结,如有疑问请联系我。
目录
结构体变量占用空间不同
为什么要字节对齐?(内存对齐)
字节对齐的规则
结构体变量占用空间不同
typedef struct data_type1{char a[2];short b;int c;
} Data_type1;
typedef struct data_type2{short a;int b; char c[2];
} Data_type2;
先看看上面两个结构体,如果有定义成对应的变量,它俩占内存空间是多少 ?使用sizeof()占用多少空间,都是8个字节大小,答案不是。
Data_type1和Data_type2结构体里的成员变量类型相同,两者的所占的空间应该是相同的,但是事实却不是如此。
经过实践编写代码输出的结果,却是这样的。
/*ubuntu gcc环境 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>#define debug_printf(value) printf(#value " ---==> %d\n", value)
#define debug_struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))
typedef struct data_type1{char a[2];short b;int c;
} Data_type1;
typedef struct data_type2{short a;int b; char c[2];
} Data_type2;
int main(int argc, char** argv){int a,b,c;a = debug_struct_member_offset(Data_type1,a);b = debug_struct_member_offset(Data_type1,b);c = debug_struct_member_offset(Data_type1,c);debug_printf(sizeof(Data_type1));debug_printf(a);debug_printf(b);debug_printf(c);a = debug_struct_member_offset(Data_type2,a);b = debug_struct_member_offset(Data_type2,b);c = debug_struct_member_offset(Data_type2,c);debug_printf(sizeof(Data_type2));debug_printf(a);debug_printf(b);debug_printf(c);
}
Data_type1和Data_type2的类型变量占用的大小分别是8和12.
为什么会出现这样的结果?
因为编译器对数据进行了优化,做了字节对齐操作,可以增加内存的使用率和数据高效得传输。
什么是字节对齐?
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,计算机并非逐个字节读取,而是以2、4、8的倍数字节块读取内存,它们会要求这些数据的首地址的值是某个数是k(通常是4或8)的倍数 ,这就是所谓的内存对齐。大白话就是,各种数据类型都要一定的规则进行排列,而不是一个接一个的排放,这就是对齐。
为什么需要字节对齐?
1、减少cpu访问变量的次数,cpu可以更快的读取数据
2、合理的使用字节对齐,可以节省内存的大小。
3、减少 cpu 访问数据的出错性(有些 cpu 必须内存对齐,否则指针访问会出错),不同硬件平台进行数据通信,数据对齐可能会不一致,需要加入伪指令进行操作,防止灾难性性bug。
字节对齐的规则
规则一:结构体变量的首地址能够被字节对齐的大小整除(gcc 缺省字节对齐大小是4)。
规则二:结构体的每个成员相对首地址的偏移是成员类型大小的整数倍。(成员自身对齐)
规则三:结构体变量的总大小是结构体里最大的成员的整数倍。(结构体本身对齐)
计算结构体变量的字节大小,以上面的例子说明
Data_type1结构体变量类型,大概这样存放的。
计算字节大小可以不关心规则一,可以被忽略。看规则二,第二个成员b的偏移是2是short大小(2)的整数倍,第三个成员c的偏移量是4是int的大小的整数倍。看规则三,总的大小是8字节,是int大小的整数倍,c成员后面不需要填内容。
Data_type1结构体变量类型
看规则二,第二个成员b的偏移是2不是int大小(4)的整数倍,成员a后面补2个字节才能被4整除,第三个成员c的偏移量是8是char的大小的整数倍。看规则三,总的大小是10字节,不是是int大小(4)的整数倍,成员c补上内容(2),直到能被4整除,所以总大小是12个字节。
在设计数据结构的时候,可以看出合理调整成员的排序,可以节省内存使用。但是需要在空间上和可读性进行权衡。
思考,结构体类型,被实体化后,占用的字节大小:
typedef struct data_type3{char a;char b; char c;
} Data_type3;
typedef struct data_type4{char a;char b[2]; //char c;
} Data_type4;
答案都是3.
有什么办法可以对字节对齐进行干预?
1、使用#prama park(n)伪指令,会对前面规则二和规则三进行干预,大白话,成员本身字节对齐和结构体本身对齐大小不能大于n,只能小,如果能理解这这句话,问题就不大了,直接看例子吧。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>#define debug_printf(value) printf(#value " ---==> %d\n", value)
#define struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))#pragma pack(4) //4字节对齐开始 对齐大小只能比4小,不能大
typedef struct
{uint32_t b; /*double 8字节对齐,这里正常是要补4字节内容,但是编译器这里规定最多只能4个字节对齐,如果是short就按2个字节对齐,只能小不拿大*/double f;
} test_t;
#pragma pack()//字节对齐结束
int main()
{int b = struct_member_offset(test_t, b);int f = struct_member_offset(test_t, f);debug_printf(sizeof(test_t));debug_printf(b);debug_printf(f);return 0;
}
运行结果:
注释#pragma pack(4) 占用空间是16.
2、使用__attribute((aligned(n))),操作结构体时,这里可以看成是对规则三进行干预,对结构体本身对齐。
typedef struct
{uint8_t a; // 偏移地址uint16_t b; // 偏移地址
}__attribute((packed)) test_t1; //按实际空间
typedef struct
{uint8_t a; // 偏移地址uint16_t b; // 前补1 偏移地址
}__attribute((aligned(4))) test_t2;
typedef struct
{uint8_t a; // 偏移地址uint16_t b; //前补1 偏移地址
}__attribute((aligned(8))) test_t3;
typedef struct
{uint8_t a; // 偏移地址uint16_t b; //前补1 偏移地址
}__attribute((aligned(16))) test_t4;
//#pragma pack()
int main()
{debug_printf(sizeof(test_t1));debug_printf(sizeof(test_t2));debug_printf(sizeof(test_t3));debug_printf(sizeof(test_t4));return 0;
}
运行结果
留个坑:
typedef struct data_type1{char a[2];short b;int c;
} Data_type1;
typedef struct data_type2{short a;Data_type1 b; //Tips: 这部分按里面最大成员大小对齐 所以要补. 至于补多少……char c[2];
} Data_type2;
sizeof(Data_type2)是多少?
答案:16
以上是结果,都是经过我测试验证成功,如有疑问,请麻烦联系我。我是小昭!
字节对齐看这篇就够了(内存对齐)相关推荐
- uiautomation遍历windows所有窗口_万字长文!滑动窗口看这篇就够了!
大家好,我是小浩.今天是小浩算法 "365刷题计划" 滑动窗口系列 - 整合篇.之前给大家讲解过一些滑动窗口的题目,但未作系统整理. 所以我就出了这个整合合集,整合工作中除了保留原 ...
- 史上最全!用Pandas读取CSV,看这篇就够了
导读:pandas.read_csv接口用于读取CSV格式的数据文件,由于CSV文件使用非常频繁,功能强大,参数众多,因此在这里专门做详细介绍. 作者:李庆辉 来源:大数据DT(ID:hzdashuj ...
- Android原生TabLayout使用全解析,看这篇就够了
前言 为什么会有这篇文章呢,是因为之前关于TabLayout的使用陆陆续续也写了好几篇了,感觉比较分散,且不成体系,写这篇文章的目的就是希望能把各种效果的实现一次性讲齐,所以也有了标题的「看这篇就够了 ...
- 【超全汇总】学习数据结构与算法,计算机基础知识,看这篇就够了【ZT帅地】2020-3-7
https://blog.csdn.net/m0_37907797/article/details/104029002 由于文章有点多,并且发的文章也不是一个系列一个系列发的,不过我的文章大部分都是围 ...
- 一文详解JavaBean 看这篇就够了
一文详解JavaBean 看这篇就够了 JavaBean的历史渊源 JavaBean的定义(通俗版) JavaBean应用 < jsp:useBean > < jsp:getProp ...
- React入门看这篇就够了
2019独角兽企业重金招聘Python工程师标准>>> 摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所 ...
- .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了
写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新手朋友),但是转念一想不如来点猛的(考虑到急性子的朋友),让你通过本文的学习就能快速的入门ASP.NET Core.既 ...
- [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
园子里关于ASP.NET Core Web API的教程很多,但大多都是使用EF+Mysql或者EF+MSSQL的文章.甚至关于ASP.NET Core Web API中使用Dapper+Mysql组 ...
最新文章
- 程序员如何才能提高自己?通过一次重构代码讲解自己的感受【有代码比较】...
- Java学习笔记(43)——Java泛型
- 开启大数据时代谷歌三篇论文-Mapreduce
- hdu 4925 Apple Tree--2014 Multi-University Training Contest 6
- js面向对象之创建对象1
- 远程工具连接mysql备份_MySQL远程连接 备份还原
- [Swagger2]分组和接口注释及小结
- 19-数据持久化-Bind Mounting
- c语言综合编程,C语言编程入门——综合练习(一)
- binder.java 565_Android跨进程抛异常的原理的实现
- 动手实验:使用 jstat 摸清线上系统的JVM运行状况
- 字母和数字符号的ASCII码对照表转
- 西电计算机学院通知,西安电子科技大学计算机科学与技术学院关于发放2020级硕士研究生正式录取通知书的通知...
- 双十一全零售领域狂欢 请了明星代言商家真的能赚到钱吗?
- 只要你懂得人性,就不怕没钱赚!
- POJ 2671 Jimmy's Bad Day ★ (区间DP)
- node.js里的天龙八部
- 【最经典的79个】软件测试面试题(内含答案)都是可以提前准备的!
- 计算机设备耗材管理制度,关于国税局计算机耗材管理办法
- CMGAN: Conformer-based Metric GAN for Speech Enhancement