stm32中使用#pragma pack(非常有用的字节对齐用法说明)
#pragma pack(4) //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐
typedef struct
{
char buf[3];//buf[1]按1字节对齐,buf[2]按1字节对齐,由于buf[3]的下一成员word a是按两字节对齐,因此buf[3]按1字节对齐后,后面只需补一空字节
word a; //#pragma pack(4),取小值为2,按2字节对齐。
}kk;
#pragma pack() //取消自定义字节对齐方式
对齐的原则是min(sizeof(word ),4)=2,因此是2字节对齐,而不是我们认为的4字节对齐。
这里有三点很重要:
1.每个成员分别按自己的方式对齐,并能最小化长度
2.复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度
3.对齐后的结构体整体长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐
补充一下,对于数组,比如:
char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐.
如果写: typedef char Array3[3];
Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度.
不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个.
声明:
整理自网络达人们的帖子,部分参照MSDN。
作用:
指定结构体、联合以及类成员的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次方;这样在处理数组时可以保证每一项都边界对齐;
这里面有四个概念值:
更改c编译器的缺省字节对齐方式:
在缺省情况下,c编译器为每一个变量或数据单元按其自然对界条件分配空间;一般地可以通过下面的两种方法来改变缺省的对界条件:
方法一:
使用#pragma pack(n),指定c编译器按照n个字节对齐;
使用#pragma pack(),取消自定义字节对齐方式。
方法二:
__attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
__attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
比如:
typedef struct
{
...
}__attribute__((aligned(4))) param_t;
综上所述,下面给出例子并详细分析:
例子一:
#pragma pack(4)
class TestB
{
public:
int aa; //第一个成员,放在[0,3]偏移的位置,
char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。由于下一成员short b是按2字节对齐,因此char a后面只需补一个空字节
short b; //第三个成员,自身长2,#pragma pack(4),取小值为2,按2字节对齐,所以放在偏移[6,7]的位置。
char c; //第四个,自身长为1,放在[8]的位置。
};
可见,此类实际占用的内存空间是9个字节。(这里有疑问?按我的理解,根据规则5,结构整体的对齐是min( sizeof( int ), pack_value ) = 4,所以sizeof( TestB ) = 12; char a 占用一个字节,后面补3个空字节;short b和char c可以放在同一4字节空间中,后面只需补一个空字节。)
例子二:
#pragma pack(2)
class TestB
{
public:
int aa; //第一个成员,放在[0,3]偏移的位置,
char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。由于下一成员short b按2字节对齐,因此char a后面只需补一个空字节
short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
char c; //第四个,自身长为1,放在[8]的位置。
};
可见结果与例子一相同,各个成员的位置没有改变,(这里有疑问?按我的理解,此时结构整体的对齐是min( sizeof( int ), pack_value ) = 2,所以sizeof( TestB ) = 10;char a后面补一个空字节;char c后面补一个空字节。)
例子三:
#pragma pack(4)
class TestC
{
public:
char a; //第一个成员,放在[0]偏移的位置,由于下一成员short b按2字节对齐,因此char a后面只弱补一个空字节
short b; //第二个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[2,3]的位置。
char c; //第三个,自身长为1,放在[4]的位置。
};
整个类的实际内存消耗是5个字节,(这里有疑问?按我的理解,整体按照min( sizeof( short ), 4 ) = 2对齐,所以结果是sizeof( TestC ) = 6。)
例子四:
struct Test
{
char x1; //第一个成员,放在[0]位置。由于下一成员short x2按2字节对齐,因此char x1后面只需补一个空字节,
short x2; //第二个成员,自身长度为2,按2字节对齐,所以放在偏移[2,3]的位置,
float x3; //第三个成员,自身长度为4,按4字节对齐,所以放在偏移[4,7]的位置,
char x4; //第四个成员,自身长度为1,按1字节对齐,所以放在偏移[8]的位置,
};
所以整个结构体的实际内存消耗是9个字节,(这里有疑问?按我的理解,考虑到结构整体的对齐是4个字节,所以整个结构占用的空间是12个字节。char x1和short x2共用一个4字节空间,后面补一个空字节;char x4后面需要补3个空字节。)
例子五:
#pragma pack(8)
struct s1
{
short a; //第一个,放在[0,1]位置,
long b; //第二个,自身长度为4,按min(4, 8) = 4对齐,所以放在[4,7]位置
};
所以结构体的实际内存消耗是8个字节。结构体的对齐是min( sizeof( long ), pack_value ) = 4字节,所以整个结构占用的空间是8个字节。
struct s2
{
char c; //第一个,放在[0]位置,
s1 d; //第二个,根据规则四,对齐是min( 4, pack_value ) = 4字节(由于s1占用了8个字节,这里为什么不是8字节??),所以放在[4,11]位置,
long long e; //第三个,自身长度为8字节,所以按8字节对齐,所以放在[16,23]位置,
};
所以实际内存消耗是24字节。整体对齐方式是8字节,所以整个结构占用的空间是24字节。
#pragma pack()
所以:sizeof(s2) = 24, char c后面是空了3个字节接着是s1 d, s1 d后面又补了4个空字节(这里有疑问??按我的理解,char c占一个字节,后面补7个字节;s1 d占8个字节;long long e占8个字节。)
stm32中使用#pragma pack(非常有用的字节对齐用法说明)的更多相关文章
- pragma pack(非常有用的字节对齐用法说明)
强调一点: #pragma pack(4) typedef struct { char buf[3]; word a; }kk; #pragma pack() 对齐的原则是min(sizeof(wor ...
- 关于C语言中结构体中的结构体成员导致的字节对齐问题
关于结构体的字节对齐是什么,就不赘述,再此附上一篇文章,介绍字节对齐:http://www.linuxsong.org/2010/09/c-byte-alignment/ 这里的结构体字节对齐的数据类 ...
- #pragma pack(push,1)与#pragma pack(1)的区别
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- (转载)关于#pragma pack(push,1)和#pragma pack(1)
转载http://www.rosoo.net/a/201203/15889.html 一.#pragma pack(push,1)与#pragma pack(1)的区别 这是给编译器用的参数设置,有关 ...
- #pragma pack(push,1)与#pragma pack(pop)
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- #pragma pack的使用
#pragma pack的作用 程序编译器对变量的存储带有一定随机性,而pragma pack是一种字节对齐方法,采用人为设定的方式将存储数据按一定格式排布.百科中提到了其一种作用:有的平台每次读都是 ...
- 【转】#pragma pack(push,1)与#pragma pack(1)的区别
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- #pragma pack
原文链接: http://www.cnblogs.com/s7vens/archive/2012/03/06/2382236.html pack 为 struct, union 和 class 等的成 ...
- #pragma pack(push,1)与#pragma pack(1)的区别(转)
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
随机推荐
- 20155234 《Java程序设计》实验四 (Android程序设计)实验报告
实验内容 基于Android Studio开发简单的Android应用并部署测试; 了解Android.组件.布局管理器的使用: 掌握Android中事件处理机制. 实验步骤 (一)Android S ...
- 20145207《Java程序设计》实验二(Java面向对象程序设计)实验报告
<Java程序设计>实验二(Java面向对象程序设计)实验报告 目录 改变 Java面向对象程序设计实验要求 实验成果 课后思考 改变 看了下之前实验二的整体,很搞笑,大图+代码,没了.. ...
- [arc068E]Snuke Line-[树状数组]
Description 传送门 Solution 假如想直接YY对于每一个d会有多少种商品满足条件,em反正我搞不定. 然后大佬的题解告诉我说:搞不定?那就不搞它啊,反过来不就得了? 好吧.我们来考虑 ...
- rsync + inotify 数据实时同步
一.rsync介绍 rsync英文全称为Remote synchronization,从软件的名称就可以看出来,Rsync具有可是本地和远程两台主机之间的数据快速复制同步镜像.远程备份的功能,这个功能 ...
- 1、maven打包 install package deploy区别
maven package:打包到本项目,一般是在项目target目录下.如果a项目依赖于b项目,打包b项目时,只会打包到b项目下target下,编译a项目时就会报错. maven install:打 ...
- 9.15 DP合集水表
9.15 DP合集水表 显然难了一些啊. 凸多边形的三角剖分 瞄了一眼题解. 和蛤蛤的烦恼一样,裸的区间dp. 设f[i][j]表示i~j的点三角剖分最小代价. 显然\(f[i][i+1]=0,f[i ...
- 接口文档神器Swagger(下篇)
本文来自网易云社区 作者:李哲 二.Swagger-springmvc原理解析 上面介绍了如何将springmvc和springboot与swagger结合,通过简单配置生成接口文档,以及介绍了swa ...
- 工作中遇到的令人头疼的bug
工作中我们会遇到形形色色的bug,但是很多bug都可以调试很明显的看出来,这种bug解决起来我们不会那么头疼但是有些却让人头疼而捉急,特别是本地运行一切正常,上传服务器就会出现bug.现在我总结几个我 ...
- 2017年4月8日Office 365 使用CSV文件导入邮件组
国内版 第一步: Import-Module msonline Connect-MsolService 输入用户名密码 第二步: Get-MsolUser" 第三步: Set-Executi ...
- Python最简编码规范
前言 本文是阅读<Python Coding Rule>之后总结的最为精华及简单的编码规范,根据每个人不同喜好有些地方会有不同的选择,我只是做了对自己来说最简单易行的选择,仅供大家参考. ...