#pragma pack(n)内存对齐

news2024/12/24 4:00:00

1. 为什么要对齐?

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

2. 对齐规则

1. 未指定#pragma pack时,系统默认的对齐模数4字节(32位机,X86系统等)。
2. 指定#pragma pack 对齐模数时,实际取pack 对齐模数和默认的最小值。
3. 结构体里面static变量,因为静态变量的存放位置与结构体实例的存储地址无关,是单独存放在静态数据区的,因此用siezof计算其大小时没有将静态成员所占的空间计算进来。

3. 举例说明

#include <stdio.h>
typedef struct student
{
  char           a;  //默认4个字节对齐,char           是1个字节,以4字节对齐,按4个字节处理
  short          b;  //默认4个字节对齐,short          是2个字节,以4字节对齐,按4个字节处理
  int            c;  //默认4个字节对齐,int            是4个字节,以4字节对齐,按4个字节处理
  float          d;  //默认4个字节对齐,float          是4个字节,以4字节对齐,按4个字节处理
  double         e;  //默认4个字节对齐,double         是8个字节,以4字节对齐,按8个字节处理
  long           f;  //默认4个字节对齐,long           是4个字节,以4字节对齐,按4个字节处理
  unsigned char  g;  //默认4个字节对齐,unsigned char  是1个字节,以4字节对齐,按4个字节处理
  unsigned short h;  //默认4个字节对齐,unsigned short 是2个字节,以4字节对齐,按4个字节处理
  unsigned int   i;  //默认4个字节对齐,unsigned int   是4个字节,以4字节对齐,按4个字节处理
}STU;
int main()
{
    printf("%d.\n", sizeof(STU));
    return 0;
}

在这里插入图片描述

分析:假如我们不使用字节对齐,那么这个结构体大小应当是1+2+4+4+8+4+1+2+4=28个字节,但是实际打印的结果确实是40个字节。这是因为编译器默认以4个字节对齐,不足4个字节(比如short和char),按4个字节处理。大于等于4个字节的就不用管。(比如double是8个字节,就按8个字节算)
但是在实际工程中,如果我们是读取一块一块的数据,这些数据都是连在一起的,比如bmp图片,前14个字节是文件信息头,紧接着是40个字节的图像信息头。如果我们不用结构体对齐操作的话。那就乱了套了,数据就读取失败。所以我们要在结构体前加上#pragma pack(1),以一个字节对齐,使用完后要加#pragma pack(),释放内存对齐。为啥要以1个字节对齐呢?是因为一般的数据类型都是大于等于1个字节的。这样的话就会按照数据类型原有的的分配。就不会错位了。

#include <stdio.h>

#pragma pack(1)		// 按照1字节对齐
typedef struct student
{
  char           a;  //设置1个字节对齐,char           是1个字节,以1字节对齐,按1个字节处理
  short          b;  //设置1个字节对齐,short          是2个字节,以1字节对齐,按2个字节处理
  int            c;  //设置1个字节对齐,int            是4个字节,以1字节对齐,按4个字节处理
  float          d;  //设置1个字节对齐,float          是4个字节,以1字节对齐,按4个字节处理
  double         e;  //设置1个字节对齐,double         是8个字节,以1字节对齐,按8个字节处理
  long           f;  //设置1个字节对齐,long           是4个字节,以1字节对齐,按4个字节处理
  unsigned char  g;  //设置1个字节对齐,unsigned char  是1个字节,以1字节对齐,按1个字节处理
  unsigned short h;  //设置1个字节对齐,unsigned short 是2个字节,以1字节对齐,按2个字节处理
  unsigned int   i;  //设置1个字节对齐,unsigned int   是4个字节,以1字节对齐,按4个字节处理
}STU;
#pragma pack()		// 释放内存对齐

int main()
{
    printf("%d.\n", sizeof(STU));
    return 0;
}

在这里插入图片描述
这回就按照每个变量的类型给出实际的结果了,1+2+4+4+8+4+1+2+4=30。

4. #pragma pack(push)和#pragma pack(pop)

#pragma pack(push):编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
#pragma pack(pop):编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。
可以知道,当我们想要一个结构体按照4字节对齐时,可以采用以下两种方式:
方式一:
可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() 进行恢复。

#pragma pack(4)
struct {
	...
}
#pragma pack()
#include <stdio.h>

#pragma pack(4)
typedef struct student
{
  char           a; // 1
  short          b; // 2
  int            c; // 4
  float          d; // 4
  double         e; // 8
}STU;
#pragma pack()


int main()
{
    printf("%d.\n", sizeof(STU));

    return 0;
}

在这里插入图片描述
方式二:

#pragma pack(push) 
#pragma pack(4)

struct {
	 ... 
}

#pragma pack(pop)

这样在push和pop之间的结构体就可以按照pack指定的字节(这里是4字节对齐方式),而pop之后的结构体按照#pragma pack(push) 前的对齐方式进行对齐。

#include <stdio.h>


#pragma pack(push)
#pragma pack(4)
typedef struct student
{
  char           a; // 1
  short          b; // 2
  int            c; // 4
  float          d; // 4
  double         e; // 8
}STU;
#pragma pack(pop)


int main()
{
    printf("%d.\n", sizeof(STU));

    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatGPT非常重要的能力居然不行,就让这个工具来拯救,让你SQL操作无忧

引言 各位好&#xff0c;相信看见这篇文章的朋友&#xff0c;应该也去体验过了chatGPT了吧~&#xff0c;确实chatGPT拉近了我们与未来科技的距离&#xff0c;所有别人火也是非常有道理的&#xff0c;为其点赞。 本文主要是关注chatGPT的SQL能力&#xff1b;因为本人从事IT教育…

用友T+数据备份与恢复方法汇总

一、正常数据备份与恢复 适合于用友T能正常登陆、正常备份的情况。 1、数据备份 以系统管理员admin登陆系统管理&#xff0c;点击“账套维护”&#xff0c;选择好需要备份的账套&#xff0c;点击“备份”&#xff0c;同时设置好备份路径&#xff0c;保存备份文件即可&#xf…

(附源码)Springboot服装网购网站 毕业设计 010234

Springboot服装网购网站 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管…

Day825.死锁问题 -Java 并发编程实战

死锁问题 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于死锁问题。 用 Account.class 作为互斥锁&#xff0c;来解决银行业务里面的转账问题&#xff0c;虽然这个方案不存在并发问题&#xff0c;但是所有账户的转账操作都是串行的&#xff0c;例如账户 A 转账户 B…

【华为上机真题 2022】完全二叉树非叶子节点后序遍历

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

不知道哪个视频软件可以一键成片?建议收藏这些软件

随着短视频平台的不断发展&#xff0c;越来越多的小伙伴加入进了短视频剪辑的行列当中。现在市面上的视频剪辑软件很多&#xff0c;但是对于新手小白来说&#xff0c;能够快速上手使用的视频编辑软件才是重要的。那你们知道一键成片视频软件哪个好吗&#xff1f;有想要制作短视…

2、基于XML的依赖注入详细配置

一、依赖注入详细配置 1、通过P名称空间为Bean注入值 1、简化setter方式注入的配置&#xff0c;可以不使用<property />子标签来为属性设置值&#xff0c;直接在<bean />标签中设置各依赖项的值。 2、注入值类型说明&#xff1a; 对于String、基本类型及其包装类使…

visio绘图小技巧

1.如何在图框的任意位置添加点&#xff1f; 先选中x点指令&#xff0c;再按住ctrl键&#xff0c;即可在任意位置画点 2.如何画出锯齿形线段&#xff1f; visio里面好像没有现成的锯齿形线段&#xff0c;所以可以利用直线反复折画&#xff0c;但是这里有个小技巧&#xff0c;就…

[附源码]JAVA毕业设计小王防疫副食品配送商城(系统+LW)

[附源码]JAVA毕业设计小王防疫副食品配送商城&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项…

获取网易云音乐开放接口api的推荐歌单

网易云音乐开放api接口 网址&#xff1a;https://binaryify.github.io/NeteaseCloudMusicApi/#/?idneteasecloudmusicapi 项目地址&#xff1a;https://github.com/Binaryify/NeteaseCloudMusicApi 下载下来之后&#xff0c;安装依赖&#xff1a;npm install 启动服务&#xf…

决策树(decision tree)

决策树构建&#xff1a;特征选择、决策树的生成和决策树的修剪。 特征选择 特征选择在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率&#xff0c;如果利用一个特征进行分类的结果与随机分类的结果没有很大差别&#xff0c;则称这个特征是没有分类能力的…

Lifeform——站在3D虚拟数字身份与元宇宙结合的风口之上

Web3和元宇宙是公认的下一个风口&#xff0c;吸引了大量用户的关注和参与。从《我的世界》中的场景编辑器&#xff0c;到DecentreLand&#xff0c;以及Sandbox中玩家对自己虚拟地块的装饰。人们在虚拟世界中举办各种活动&#xff0c;比如演唱会、节日庆祝或者比赛、游戏甚至婚礼…

PrizmDoc Viewer添加了新的Excel渲染选项

PrizmDoc Viewer添加了新的Excel渲染选项 添加了新的Microsoft Excel渲染选项。PrizmDoc Viewer现在提供了在MSO渲染模式下查看Excel文档时自动调整单元格宽度和/或高度的选项。 PrizmDoc Viewer Microsoft Office转换附加选项现在与运行在Microsoft Windows Server 2019/2022上…

谷粒商城8:分布式锁使用和springcache的整合

1.分布式锁redisson使用 ①分布式锁简介 ②分布式锁学习过程 ③最终分析 加入锁为原子操作&#xff1a;设置过期时间设置锁 删除锁为原子操作&#xff1a;业务流程删除锁 将锁的过期时间调长 ④Redisson的使用 引入依赖程序化配置使用 创建redisson客户端 Redisson.create(…

6.论文学习Modality-aware Mutual Learning for Multi-modal Medical Image Segmentation

目录一.摘要1.背景解决方法1.如何有效整合来自多模态医学图像的信息2.如何处理常见模式缺失的情况2.解决1.ML2.MA3.结论二.方法2.1模态特定模型Modality-specific Model2.2 Modality-Aware Module2.3互学策略Mutual Learning Strategy三.实验与结果3.1数据集和评估指标3.2运行细…

杨校老师课堂之Spring Boot框架面试题【开发工程师面试前必看】

1. 什么是 Spring Boot&#xff1f; Spring Boot 是 Spring 开源组织下的子项目&#xff0c;是 Spring 组件一站式解决方案&#xff0c;主要是简化了使用Spring 的难度&#xff0c;简省了繁重的配置&#xff0c;提供了各种启动器&#xff0c;使开发者能快速上手。 2. 为什么要用…

c#入门-别名引用

别名引用 如果你引用的命名空间中出现了同名的类&#xff0c;那么会无法判断你使用的类型。 当然&#xff0c;你可以使用完全限定名。 或者&#xff0c;你可以为其中一个类型指代别名。 使用引用命名空间语句&#xff0c;为一个标识符赋值一个类型。 可以使用这个标识符代替…

基于java+springmvc+mybatis+jsp+mysql的通信簿管理系统

项目介绍 前端页面&#xff1a; 功能&#xff1a;首页、日志信息、心情日志、相册信息、个人中心、后台管理 管理员后台页面&#xff1a; 功能&#xff1a;主页、个人中心、用户管理、日志信息管理、日志类别管理、心情日志管理、相册信息管理、系统管理 开发环境 开发语言&…

C#【必备技能篇】Marshal是什么?怎么用?

文章目录学习来源&#xff1a;MSDN官方文档一、Marshal是什么&#xff1f;1、英文释义&#xff1a;2、在MSDN中的定义&#xff1a;3、通俗理解&#xff1a;二、Marshal怎么用&#xff1f;【主要以一些实例来了解】1、Marshal下的方法_部分截图【C#源码】&#xff1a;2、一些示例…

自定义RBAC(3)

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; RBAC类型的权限&#xff0c;本质上是一种对资源访问路径的控制&#xff0c;且具有典型的树型层次结构。而树型结构&#xff0c;天然地就有父结点和子结点的关系以…