pragma pack 对齐用法

深入解析C/C++中的__attribute__((packed)):内存对齐与紧打包技术 本文将详细介绍__attribute__((packed))的作用、使用场景及注意事项,帮助开发者更好地掌握内存对齐与紧打包技术。((packed))是C/C++中实现紧打包的一个重要工具,掌握其使用方法和注意事项,有助于我们在特定场景下优化内存布局。在性能要求较高的场景中,应谨慎使用。((packed))是GCC和Clang等编译器的扩展属性,用于告诉编译器对指定的结构体或联合体进行紧打包处理,消除成员间的填充。使用紧打包的结构体时,需要注意成员的访问顺序,避免因内存对齐导致的问题。 阅读详情

      为了搞清楚#pragma pack(n)的写法,Test一下。下面这段测试代码贴在任意一个控制台程序的面前面即可。

 

    另转一篇详细的文章:http://www.360doc.com/content/10/0124/00/722458_14261654.shtml

 

#pragma pack(n) 对齐用法详解(转载)

 

 

什么是对齐,以及为什么要对齐:
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为 32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
对齐的实现
通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择时候目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。
但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。
  

作用:
指定结构体、联合以及类成员的packing alignment;

语法:
#pragma pack( [show] | [push | pop] [, identifier], n )

说明:
1,pack提供数据声明级别的控制,对定义不起作用;
2,调用pack时不指定参数,n将被设成默认值;
3,一旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降
;

语法具体分析:
1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;
2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;
3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;
4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;
5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。

重要规则:
1,复杂类型中各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个类型的地址相同;
2,每个成员分别对齐,即每个成员按自己的方式对齐,并最小化长度;规则就是每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数中较小的一个对齐;
3,结构、联合或者类的数据成员,第一个放在偏移为0的地方;以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度两个中比较小的那个进行;也就是说,当#pragma pack指定的值等于或者超过所有数据成员长度的时候,这个指定值的大小将不产生任何效果;
4,复杂类型(如结构)整体的对齐<注意是“整体”>是按照结构体中长度最大的数据成员和#pragma pack指定值之间较小的那个值进行;这样在成员是复杂类型时,可以最小化长度;
5,结构整体长度的计算必须取所用过的所有对齐参数的整数倍,不够补空字节;也就是取所用过的所有对齐参数中最大的那个值的整数倍,因为对齐参数都是2的n次方;这样在处理数组时可以保证每一项都边界对齐;

对齐的算法:
由于各个平台和编译器的不同,现以本人使用的gcc version 3.2.2编译器(32位x86平台)为例子,来讨论编译器对struct数据结构中的各成员如何进行对齐的。   

在 相同的对齐方式下 ,结构体内部数据 定义的顺序不同 ,结构体整体占据内存空间也 不同 ,如下:
设结构体如下定义:
struct A
{
     int      a;
     char    b;
     short c;
};
结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个。所以A用到的空间应该是7字节。但是因为编译器要对数据成员在空间上进行对齐。所以使用sizeof(strcut A)值为 8 。
现在把该结构体调整成员变量的顺序。
struct B
{
     char    b;
      int      a;
      short c;
};
这时候同样是总共7个字节的变量,但是sizeof(struct B)的值却是 12 。
下面我们使用预编译指令#progma pack (value)来告诉编译器,使用我们指定的对齐值来取代缺省的。
#progma pack (2) /*指定按2字节对齐,等价于#pragma pack(push,2)*/
struct C
{
      char b;
     int      a;
     short c;
};
#progma pack () /*取消指定对齐,恢复缺省对齐,等价于#pragma pack(pop)*/
sizeof(struct C)值是 8 。

修改对齐值为1:
#progma pack (1) /*指定按1字节对齐*/
struct D
{
      char b;
      int      a;
      short c;
};
#progma pack () /*取消指定对齐,恢复缺省对齐*/
sizeof(struct D)值为 7 。

对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
  

这里面有四个概念值:
1.数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。
2.指定对齐值:#progma pack (value)时的指定对齐值value。
3.结构体或者类的自身对齐值:其数据成员中自身对齐值最大的那个值。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0". 而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。
例子分析:
分析例子B;
struct B
{
      char b;
      int      a;
     short c;
};
假设B从地址空间 0x0000 开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值 默认为4 。

第一个成员变量b的自身对齐值是 1 ,比指定或者默认指定对齐值 4 小,所以其有效对齐值为 1 ,所以其存放地址 0x0000 符合 0x0000%1=0 .

第二个成员变量a,其自身对齐值为 4 ,所以有效对齐值也为 4 ,所以只能存放在起始地址为 0x0004 到 0x0007 这四个连续的字节空间中,符合 0x0004%4=0 , 且紧靠第一个变量。

第三个变量c,自身对齐值为 2 ,所以有效对齐值也是 2 ,可以存放在 0x0008 到 0x0009 这两个字节空间中,符合 0x0008%2=0 。所以从0x0000到0x0009存放的都是B内容。

再看数据结构 B的自身对齐值 为其变量中最大对齐值( 这里是b )所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节 ,(10+2)%4=0 。所以 0x0000A 到 0x000B 也为结构体B所占用。故B从0x0000到0x000B共有12个字节, sizeof(struct B)=12 ;

同理,分析上面例子C:
#progma pack (2) /*指定按2字节对齐*/
struct C
{
      char    b;
     int      a;
     short c;
};
#progma pack () /*取消指定对齐,恢复缺省对齐*/
第一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合0x0000%1=0;

第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续字节中,符合0x0002%2=0。

第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放在0x0006、0x0007中,符合0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。

又C的自身对齐值为4,所以C的有效对齐值为2。又8%2=0,C只占用0x0000到0x0007的八个字节。所以 sizeof(struct C)=8.

gcc: attribute: packed 在C语言中,enum类型默认占用4个字节的内存空间。然而,通过使用__attribute__((packed))属性,可以强制编译器将enum类型压缩到最小可能的字节数。例如,在给定的代码中,enum类型abc在没有packed属性时占用4个字节,而加上packed属性后,它仅占用1个字节。这是因为packed属性告诉编译器尽可能紧凑地存储数据,减少内存占用。这一特性在处理内存敏感的应用时非常有用,但需要注意可能带来的对齐问题。 阅读详情

相关推荐

【Unity Animation 2D】从零到一:骨骼绑定与IK动画实战指南

本文详细介绍了Unity中2D骨骼绑定与IK动画的实战流程,从角色素材准备、骨骼系统创建到权重绘制和IK设置,逐步指导开发者掌握2D动画制作技巧。通过反向动力学(IK)技术,实现更自然的角色动画效果,适用于游戏开发和动画制作。

weixin_30430677的博客 370

Linux下__attribute__((visibility (“default“)))的使用 + __attribute__((packed))详解

一: 在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中,有个visibility属性,可见属性可以应用到函数、变量、模板以及C++类。 限制符号可见性的原因:从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。 “default”:用它定义的符号将被导出,动态库中的函

君君的博客 5857

win10下Miracast无线投屏使用教程及异常解决方案(超详细)

文章目录一、什么是Miracast?二、主流的无线投屏技术有哪些特点?三、如何查看自己的win10电脑是否支持Miracast无线投屏功能?四、win10电脑如何使用Miracast无线投屏功能? 一、什么是Miracast? Miracast是由Wi-Fi联盟于2012年所制定,以Wi-Fi直连(Wi-Fi Direct)为基础的无线显示标准。支持此标准的3C设备(如智能手机、电视、投影、电脑等...

帅气的小白的博客 44万+

C语言__attribute__(packed)属性

在公司实习的时候,看到了这个属性的应用,做个总结: 其实很简单:程序中没有__attribute__(packed),优化对齐,一般是4字节对齐,有的话,紧凑型,不对齐,是多少就是多少。上代码: #include<stdio.h> struct unpacked_str{ char c; int x; }; struct packed_str{ char c; int x; }_...

salmonwilliam的博客 6906

电源完整性之Cadence Sigrity Power DC_电热协同仿真

之前和大家分享过电源完整性之仿真设计原理链接: link.今天接着上一篇文章总结一下电源直流压降的的仿真操作流程及一些simulation中的设置参数,用到的是Cadence Sigrity 中的Power DC组件,来操作一下电热协同仿真,下面开始享受仿真的快乐吧: 第0步:仿真简介 电热协同仿真把电和热相互的影响考虑到了一起。因为电导率并不是固定不变的,而是和温度有关,随着温度的升高导电率会下降。同样电流流径电阻的时候会产生热量,此热量为焦耳热。因此为了获得准确的仿真信息,应考虑电与热的互相影响,进行电

刘小同学的博客 1万+

基于单片机控制的开关电源设计

采用开关电源技术和MCU模块,凭借可靠性高、易于调适的特点,可以更高效地发挥出二者的优势,从而实现更好的组合。stm32的起动模式是通过Boot0和Boot1两个管脚的高低电平来决定的,当stm32被供电之后,这两个管脚的电平。在 VCC上,键盘的一头(列线)被连接到 VCC上,而在“0”的编程输出中,则用来进。,在开关管打开的情况下,由输入电力供给电流,感应装置存储   Buck变换器是一种非隔离式的电压转换器[10]整流电路对输入电压进行整流,再经过滤波电路,即Dc电压是直流/直流变换器的直流输入。

QQ1694456187的博客 2308

C语言结构体字节对齐(内存对齐)之#pragma pack和__attribute__((packed)的使用

在不使用和本文主要讨论如何使用#pragma pack和__attribute__((packed)等选项来自定义字节对齐大小。使用pack功能将数据结构进行打包,以减小应用程序对内存的占用,这一点在嵌入式系统中,尤其是需要存储和访问大量的时候,显得尤其重要。如果没有使用#pragma pack和__attribute__((packed)等选项,将数据结构进行打包。编译器为了提高对数据成员的访问速度,通常会在不同大小的数据成员之间插入空白内存(padding),进行补齐操作,即内存对齐。

DayDayUp 1万+

论文阅读笔记:Extended Vision Transformer (ExViT) for Land Use and Land Cover Classification

注意力机制驱动的深度模型最近取得了成功,如最具代表性的视觉转换器(ViT),吸引了一波高级研究来探索它们对更广泛领域的适应。然而,遥感(RS)领域中基于Transformer的方法更关注单模态数据,这可能会在充分利用不断增长的多模态地球观测数据时失去可扩展性。为此,我们提出了一种新的多模式深度学习框架,通过在最小修改的情况下扩展传统的ViT,针对土地利用和土地覆盖(LULC)分类任务。

嗑研狗的日常 945

关于pragma pack的用法 字节对齐

一个很重要的参数 #pragma pack(n) 数据边界对齐方式: 以如下结构为例: struct {                     char a;                     WORD b; DWORD c;                     char d;                    } 在Windows默认结构大小: sizeof

gumingyaotangwei 的专栏 525

Cadence ADE实战:1GHz VCO相位噪声仿真全流程(附PSS/Pnoise避坑指南)

本文详细介绍了在Cadence ADE环境中对1GHz VCO进行相位噪声仿真的完整流程。重点剖析了PSS(周期性稳态分析)和Pnoise(周期性噪声分析)两大核心引擎的关键参数设置与避坑指南,帮助射频与模拟IC设计者准确评估VCO性能,解决仿真不收敛、结果异常等常见问题。

rock5的博客 670

SAR ADC和sigma delta ADC的区别

0、ADC基本概念 ADC,即analog to digital converter,模拟到数字的转换器,简称模数转换器。 为什么需要ADC?因为现实的世界中,电信号是连续的,例如心电信号,或者声音信号,这些连续的信号被称为“模拟信号”。 图1:心电信号 图2:声音信号 然而这种连续的信号是无法被计算机处理的,计算机只认识0和1组成的“数字信号“。ADC就充当了这样一个桥梁,将“模拟信号”转换为计算机能识别的“数字信号”。举个例子,当前的心电电压为1.2V(实际没有这么高),ADC可能会得

长河柱天的博客 2万+

pragma pack(n) 对齐用法详解

什么是对齐,以及为什么要对齐: 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其

wince--linux的专栏 696

ArcMap|使用模型构建器将kml文件批量转图层

参考:https://www.jianshu.com/p/6de18f846024 第一步:打开模型构建器,拖入kml转图层工具 第二步:插入文件迭代器 第三步:双击“迭代文件”,选择kml所在文件夹 第四步:将“File.kml”与“KML转图层”连接,点击“输入KML文件” 第五步:双击“KML转图层”,更改输出位置,输出数据名称改为%名称% 第六步:运行模型 得到结果: ...

个人学习笔记 3601

关于pragma pack的用法 C++中的内存对齐问题

关于pragma pack的用法 C++中的内存对齐问题2009-02-19 12:36<br /> <br />    首先请大家先看下面代码:<br />     typedef struct<br />     {<br />       UINT32 NumElements;<br />       union<br />       {<br />          UINT32 ObjectHandle;<br />        }Entry;<br

abin_gha的专栏 797

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

pragma pack(非常有用的字节对齐用法说明)

强调一点: #pragma pack(4) typedef struct {     char buf[3];     word a; }kk; #pragma pack() 对齐的原则是min(sizeof(word ),4)=2,因此是2字节对齐,而不是我们认为的4字节对齐。 这里有三点很重要: 1.每个成员分别按自己的方式对齐,并能最小

飞翔在北京的博客 608

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

关于pragma pack的用法C++中的内存对齐问题

首先请大家先看下面代码: typedef struct { UINT32 NumElements; union { UINT32 ObjectHandle; }Entry; }STR_ARRAY, *PSTR_ARRAY; 还有这两句#pragma pack(push, 1) #pragma pack(pop) #pragma pack( [ n ] ) 该指令指定结构和联

dxy408460910的专栏 670

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

关于pragma pack的用法(四) C++中的内存对齐问题

首先请大家先看下面代码:     typedef struct     {       UINT32  NumElements;       union       {          UINT32  ObjectHandle;        }Entry;      }STR_ARRAY, *PSTR_ARRAY;     还有这两句#pragma pack(push, 1)

行云织梦 521

关于pragma pack的用法--------------C++中的内存对齐问题

 首先请大家先看下面代码:    typedef struct    {      UINT32  NumElements;      union      {         UINT32  ObjectHandle;       }Entry;     }STR_ARRAY, *PSTR_ARRAY;    还有这两句#pragma pack(push, 1)    #pragma pac

在AC与WA间徘徊 2229
上一篇: 通信和通讯有什么区别?
下一篇: 在VC环境中调试ISAPI程序
UU_Yang
博客等级 码龄23年 926粉丝 213原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值