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

时间:2022-12-06 08:48:25

强调一点:

#pragma pack(4)

typedef struct

{

char buf[3];

word a;

}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)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

综上所述,下面给出例子并详细分析:

例子一:
#pragma pack(4)
class TestB
{
public:
int aa;
//第一个成员,放在[0,3]偏移的位置,
  char a; //第二个成员,自身长为1,#pragma
pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
  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;

例子二:
#pragma pack(2)
class TestB
{
public:
int aa;
//第一个成员,放在[0,3]偏移的位置,
  char a; //第二个成员,自身长为1,#pragma
pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
  short b; //第三个成员,自身长2,#pragma
pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
  char c;
//第四个,自身长为1,放在[8]的位置。
};
可见结果与例子一相同,各个成员的位置没有改变,但是此时结构整体的对齐是min( sizeof(
int ), pack_value ) = 2,所以sizeof( TestB ) = 10;

例子三:
#pragma pack(4)
class TestC
{
public:
char a;
//第一个成员,放在[0]偏移的位置,
  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,按2字节对齐,所以放在偏移[2,3]的位置,
float x3;
//第三个成员,自身长度为4,按4字节对齐,所以放在偏移[4,7]的位置,
char x4;
//第四个陈冠,自身长度为1,按1字节对齐,所以放在偏移[8]的位置,
};
所以整个结构体的实际内存消耗是9个字节,但考虑到结构整体的对齐是4个字节,所以整个结构占用的空间是12个字节。

例子五:
#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字节,所以放在[4,11]位置,
long long e;
//第三个,自身长度为8字节,所以按8字节对齐,所以放在[16,23]位置,
};
所以实际内存消耗是24自己,整体对齐方式是8字节,所以整个结构占用的空间是24字节。

#pragma pack()
所以:
sizeof(s2) = 24, s2的c后面是空了3个字节接着是d。

pragma pack(非常有用的字节对齐用法说明)的更多相关文章

  1. stm32中使用#pragma pack(非常有用的字节对齐用法说明)

    #pragma pack(4)   //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐 typedef struct { char buf[3];//bu ...

  2. 字节对齐#pragma pack

    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对 ...

  3. c++字节对齐编译器指令#pragma

    第一种 #pragma pack(push, 1) // 先把当前对齐设置压栈,再设置为1字节对齐 struct S { char a; ]; }; #pragma pack(pop) // 恢复先前 ...

  4. #pragma pack(push,1)与#pragma pack(1)的区别

    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对 ...

  5. 字节对齐导致的iOS EXC_ARM_DA_ALIGN崩溃

    本文原链接: http://www.cnblogs.com/zouzf/p/4455167.html 先看一下这个链接:http://www.cnblogs.com/ren54/archive/201 ...

  6. (转载)关于#pragma pack(push,1)和#pragma pack(1)

    转载http://www.rosoo.net/a/201203/15889.html 一.#pragma pack(push,1)与#pragma pack(1)的区别 这是给编译器用的参数设置,有关 ...

  7. #pragma pack(push,1)与#pragma pack(pop)

    这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对 ...

  8. c编译器字节对齐指令

    #pragma pack (n)             作用:C编译器将按照n个字节对齐.#pragma pack ()               作用:取消自定义字节对齐方式. #pragma ...

  9. #pragma pack的使用

    #pragma pack的作用 程序编译器对变量的存储带有一定随机性,而pragma pack是一种字节对齐方法,采用人为设定的方式将存储数据按一定格式排布.百科中提到了其一种作用:有的平台每次读都是 ...

随机推荐

  1. Angular2学习笔记——Observable

    Reactive Extensions for Javascript 诞生于几年前,随着angular2正式版的发布,它将会被更多开发者所认知.RxJs提供的核心是Observable对象,它是一个使 ...

  2. ZendStudio导入一个已有的网站

    解决方法:新建'PHP Project',选择'Create project at existiong location(from existing source)',路径指向你的网站根目录.

  3. Binder机制1---Binder原理介绍

    1.Binder通信机制介绍 这篇文章会先对照Binder机制与Linux的通信机制的区别,了解为什么Android会另起炉灶,採用Binder.接着,会依据Binder的机制,去理解什么是Servi ...

  4. C程序内存分配

    在多任务操作系统中的每一个进程都运行在一个属于它自己的内存沙盘中.这个沙盘就是虚拟地址空间(virtual address space),在32位模式下它总是一个4GB的内存地址块.这些虚拟地址通过页 ...

  5. source install sshpass in aix

    1.源码下载:   wget https://nchc.dl.sourceforge.net/project/sshpass/sshpass/1.06/sshpass-1.06.tar.gz 2.解压 ...

  6. POJ-2236.WireleseNetwork.(并查集)

    Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 43199   Accepted: 178 ...

  7. google sitemap

    引言 刚开始以为要一个绿色快速通道网页,涵盖常用的地址链接,以便于google的爬虫统计数据,然后看了google sitemap站点文档,原来站点地图是一种文件,您可以通过该文件列出您网站上的网页, ...

  8. spring tool suite处理 maven项目名称红色感叹号的问题

    今天构建一个springboot项目时,发现项目有个红色感叹号,但是pom.xml跟Build Path 都没问题. 解决方案: 选择 Windows --> show view --> ...

  9. Java SE学习【三】——JDBC

    最近学到了数据库与java的jdbc方面,还有个DAO模式,写一下自己的理解,后期有什么不对的再改. 一.数据库三范式的理解 记得以前上课时,也上了一学期的“数据库系统原理”,给我们上课的老师算是渣渣 ...

  10. PyQt5--CustomizeSignal

    # -*- coding:utf-8 -*- ''' Created on Sep 14, 2018 @author: SaShuangYiBing Comment: This example is ...