精华内容
下载资源
问答
  • #pragma pack(push,1)与#pragma pack(1)的区别
    2020-04-26 18:50:27

    前言:今天看师傅的代码,我还以为是师傅写了个bug,兴致冲冲的改掉。结果细想之下发现我皮皮马就是个瓜皮,幸亏没跟师傅说他写了个bug,不然肯定得被笑死了。

    一、事情发生始末

    下面就先把涉及到的代码给大家看一下:

    typedef struct
    {
        Uint16 wSerialId;      
        Uint16 wProtocolFlag;
        Uint16 wMsgLen; 
        Uint8  byDevAddr; 
    }TMDBusTcpHead;`
    
    

    这里定义了一个Modbus协议的消息头的结构体,里面4个数据共7个字节,但是由于编译器字节对齐的原因,结构体占8个字节(原因在其他博客中细谈)。

    项目是收到Modbus协议数据_recvBuf进行解析,要将指针偏移到数据的协议头之后,也就是_recvBuf[7]这个位置。下面是我师傅写的地址偏移代码:

    char* NetIOMBusTcpImpl::getmsgBuf()
    {
        return &_recvBuf[sizeof(TMDBusTcpHead)];
    }
    

    看到这段代码之后,我瞬间心想:“握草,我读书少不要骗我。编译器字节对齐sizeof(TMDBusTcpHead)不是8吗?”然后我就改掉了。这绝对是我师傅写的时候忘记了,绝对是这个原因(心中窃喜,嘿嘿嘿)。

    冷静下来,有看了一遍代码,发现事情并没有这么简单,#pragma pack(push, 1)和#pragma pack(pop)这两行代码,我之前没注意(其实是没用过,不知道就自动忽略了)。然后去上网搜了一下它的用法,发现果然还是太年轻了,师傅就是师傅
    -_-.

    下面是#pragma pack(push,1)与#pragma pack(1)的用法与区别:

    二、#pragma pack(push,1)与#pragma pack(1)的用法与区别:

    1. 编译器默认字节对齐:

    首先粗略讲一下编译器字节对齐的问题,比如上面的结构体:

    typedef struct
    {
        Uint16 wSerialId;      
        Uint16 wProtocolFlag;
        Uint16 wMsgLen; 
        Uint8  byDevAddr; 
    }TMDBusTcpHead;`
    

    若不用#pragma pack(1)和#pragma pack()括起来,编译会按默认方式对齐(成员数据中的数据类型最大的对齐)。即按照Uint16(2字节对齐)
    字节(Uint16)对齐,即sizeof(TMDBusTcpHead) = 8;

    #pragma pack(push,1)与#pragma pack(1)的作用是给编译器用的参数设置,关于结构体内存的字节对齐,#pragma pack是指定数据在内存中的对齐方式。

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

    #pragma pack(n)				//作用:C编译器按照n个字节对齐
    #pragma pack()				//作用:取消自定义对齐方式
    
    #pragma pack(push, 1)		//作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐
    #pragma back(pop)			//作用:恢复对齐状态
    

    #pragma pack(push, 1)可能会比前者更优一点,但是二者其实也没有什么大的区别,比如:

    #prama pack(push)			//保持字节对齐状态
    #pragma pack(4)				//设定为4字节对齐
    相当于:#pragma  pack (push,4)  
    
    更多相关内容
  • 下面小编就为大家带来一篇浅谈C语言的字节对齐 #pragma pack(n)2。小编觉得挺不错的现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。 但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢? 此时,#pragma pack(push) ...

    我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。

    但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢?

    此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。

    看测试代码:(说明,64位GCC,默认8字节对齐)

    屏蔽了的代码选别看,只看这个结构体,在默认8字节对齐的方式下,sizeof大小为24个字节,这不再做分析,之前随笔分析过了。

    然后我加上强制4字节对齐之后:

    那么现在,我再新建一个结构体B,内容和结构体C一样,只是对齐方式向分别采取不同的方式:

    复制代码

    #include <stdio.h>
    
    #pragma   pack(4) 
    struct C {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack() 
    struct B {
        double d;
        char b;
        int a;
        short c;
    };

    复制代码

    像上面那样处理之后,输出:先打印结构C,再打印结构B

    这说明了,在强制4字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。

    #pragma pack() 能够取消自定义的对齐方式,恢复默认对齐。

    继续测试:

    复制代码

    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };

    复制代码

    输出:

    好像没什么作用的感觉,那么再加上一个#pragma pack(push)试试呢?

    复制代码

    #include <stdio.h>
    
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n",sizeof(struct CC),sizeof(struct BB));
        return 0;
    }

    复制代码

    这样似乎改变了,有不同的地方体现了出来。

    #pragma pack(push):

    英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。

    #pragma pack(pop):

    英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。

    push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。

    这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma   pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;

    也可以使用:

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

    struct。。。

    #pragma pack(pop)

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

    eg:

     

    复制代码

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop)
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    复制代码

     

    先按照2字节对齐,然后push保存2字节对齐,然后又强制4字节对齐,打印CC为20字节,然后强制1字节对齐,打印BB为15字节,然后pop,pop会让编译器回到push之前的对齐方式(这里是2字节对齐),打印AA(按照2字节对齐)16字节。

     

     注意,#pragma pack() 取消自定义对齐方式,恢复默认方式,而push之后pop是回到push指令之前的对齐方式。

    eg:

    复制代码

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack()
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    复制代码

    只把pop改成pack()打印如下:

    最后回到的不是2字节对齐,而是默认的8字节对齐。

    还有延伸点:

    上图红色处等价于下面屏蔽的两句。

    语法:
    #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的数值,以字节为单位;

    另外:

    __attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
    __attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐

     

     

    1.什么是对齐?为什么要对齐?

    现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
    各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。
    2.pragma pack语法

    用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题,有时候为了内存对齐需要补齐空字节。通常写程序的时候,不需要考虑对齐问题。编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。
    语法:#pragma pack( [show] | [push | pop] [, identifier], n )
    作用:指定结构,联合和类的包对齐方式(pack alignment)
    show(optical):显示当前packing aligment的字节数,以warning message的形式显示。
    push(optical):
    Pushes the current packing alignment value on the internal compiler stack, and sets the current packing alignment value to n. If n is not specified, the current packing alignment value is pushed.
    pop(optical):
    Removes the record from the top of the internal compiler stack. If n is not specified with pop, then the packing value associated with the resulting record on the top of the stack is the new packing alignment value. If n is specified, for example, #pragma pack(pop, 16), n becomes the new packing alignment value. If you pop with identifier, for example, #pragma pack(pop, r1), then all records on the stack are popped until the record that hasidentifier is found. That record is popped and the packing value associated with the resulting record on the top of is the stack the new packing alignment value. If you pop with an identifier that is not found in any record on the stack, then the pop is ignored.
    identifier(optional):
    When used with push, assigns a name to the record on the internal compiler stack. When used with pop, pops records off the internal stack until identifieris removed; if identifier is not found on the internal stack, nothing is popped.
    n (optional):
    Specifies the value, in bytes, to be used for packing. If the compiler option /Zp is not set for the module, the default value for n is 8. Valid values are 1, 2, 4, 8, and 16. The alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.
    3.结构体对齐规则

    结构体中各个成员按照它们被声明的顺序在内存中顺序存储。
    1)将结构体内所有数据成员的长度值相加,记为sum_a; 
    2)将各数据成员内存对齐,按各自对齐模数而填充的字节数累加到和sum_a上,记为sum_b。对齐模数是【该数据成员所占内存】与【#pragma pack指定的数值】中的较小者。
    3)将和sum_b向结构体模数对齐,该模数是【#pragma pack指定的数值】、【未指定#pragma pack时,系统默认的对齐模数8字节】和【结构体内部最大的基本数据类型成员】长度中数值较小者。结构体的长度应该是该模数的整数倍。
    3.1 基本数据类型所占内存大小


    以下例子均按32bit编译器处理。
    3.2 Test1

    #pragma pack(4)
    struct Test1
    {
        char c;
        short sh;
        int a;
        float f;
        int *p;
        char *s;
        double d;
    };
    总共占28Bytes。 c的偏移量为0,占1个Byte。sh占2个Byte,它的对齐模数是2(2<4,取小者),存放起始地址应该是2的整数倍,因此c后填充1个空字符,sh的起始地址是2。a占4个Byte,对齐模数是4,因此接在sh后存放即可,偏移量为4。f占4个字节,对齐模数是4,存放地址是4的整数倍,起始地址是8。p,s的起始地址分别是12,16。d占8个字节,对齐模数是4(4<8),d从偏移地址为20处存放。存放后结构体占28个字节,是4的整数倍不用补空字符。

    struct Test2
    {
        char c;
        double d;
        int a;
        short sh;
        float f;
        int *p;
        char *s;        
    };
    将Test1个变量的顺序换一下位置,结构体Test2占用内存32Byte,可见写结构体时,将各个变量按所占内存从小到大排列所占结构体所占内存较小。


     
    3.3关于静态变量static

    静态变量的存放位置与结构体实例的存储地址无关,是单独存放在静态数据区的,因此用siezof计算其大小时没有将静态成员所占的空间计算进来。

    #pragma pack(4)
    struct Test3
    {
        char c;
        short sh;
        int a;
        float f;
        int *p;
        char *s;
        double d;
        static double sb;
        static int sn;
    };
    sizeof(Test3)=28

    3.4关于类

    空类是会占用内存空间的,而且大小是1,原因是C++要求每个实例在内存中都有独一无二的地址。

    (一)类内部的成员变量:

    普通的变量:是要占用内存的,但是要注意对齐原则(这点和struct类型很相似)。
    static修饰的静态变量:不占用内容,原因是编译器将其放在全局变量区。
    (二)类内部的成员函数:

    普通函数:不占用内存。
    虚函数:要占用4个字节,用来指定虚函数的虚拟函数表的入口地址。所以一个类的虚函数所占用的地址是不变的,和虚函数的个数是没有关系的
    #pragma pack(4)
    class cBase{};
    sizeof(cBase)=1

    3.4.1 不包含虚函数的类

    #pragma pack(4)
    class CBase1
    {
    private:
        char c;
        short sh;
        int a;
    public:
        void fOut(){ cout << "hello" << endl; }
    };
    不包含虚函数时,对于类中的成员变量按结构体对齐方式处理,普通函数函数不占内存。sizeof(CBase1)=8
    3.4.2 包含虚函数的类

    #pragma pack(4)
    class CBase2
    {
    private:
        char c;
        short sh;
        int a;
    public:
        virtual void fOut(){ cout << "hello" << endl; }
    };
    包含虚函数时,类中需要保存虚函数表的入口地址指针,即需要多保存一个指针。这个值跟虚函数的个数多少没有关系。sizeof(CBase2)=12
    3.4.3 子类

    子类所占内存大小是父类+自身成员变量的值。特别注意的是,子类与父类共享同一个虚函数指针,因此当子类新声明一个虚函数时,不必在对其保存虚函数表指针入口。
    #pragma pack(4)
    class CBase2
    {
    private:
        char c;
        short sh;
        int a;
    public:
        virtual void fOut(){ cout << "virtual 1" << endl; }
    };
    class cDerive :public CBase
    {
    private :
        int n;
    public:
        virtual void fPut(){ cout << "virtual 2"; }
    };

    sizeof(cDerive)= sizeof(cBase)+sizeof(int n) = 16
     

    展开全文
  • 前言 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定...此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。 看测试代码:(说明,64位GCC,默认8字节对齐) 屏蔽了的代...

    前言

    我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。
    但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢?
    此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。
    看测试代码:(说明,64位GCC,默认8字节对齐)
    在这里插入图片描述
    屏蔽了的代码先别看,只看这个结构体,在默认8字节对齐的方式下,sizeof大小为24个字节,这不再做分析,之前随笔分析过了。

    pragma pack()

    然后我加上强制4字节对齐之后:
    在这里插入图片描述
    那么现在,我再新建一个结构体B,内容和结构体C一样,只是对齐方式向分别采取不同的方式:

    #include <stdio.h>
    
    #pragma   pack(4) 
    struct C {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack() 
    struct B {
        double d;
        char b;
        int a;
        short c;
    };

    像上面那样处理之后,输出:先打印结构C,再打印结构B
    在这里插入图片描述
    这说明了,在强制4字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。
    #pragma pack() 能够取消自定义的对齐方式,恢复默认对齐。

    pragma(pop) & pragma pack(push)

    继续测试:

    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };

    输出:
    在这里插入图片描述
    好像没什么作用的感觉,那么再加上一个#pragma pack(push)试试呢?

    #include <stdio.h>
    
    #pragma pack(push) 
    #pragma   pack(4) 
    
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
    
    #pragma pack(pop) 
    
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n",sizeof(struct CC),sizeof(struct BB));
        return 0;
    }

    在这里插入图片描述
    这样似乎改变了,有不同的地方体现了出来。
    #pragma pack(push):
    英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
    #pragma pack(pop):
    英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。
    push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。
    这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;
    也可以使用:

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

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

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack(pop)
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    在这里插入图片描述
    先按照2字节对齐,然后push保存2字节对齐,然后又强制4字节对齐,打印CC为20字节,然后强制1字节对齐,打印BB为15字节,然后pop,pop会让编译器回到push之前的对齐方式(这里是2字节对齐),打印AA(按照2字节对齐)16字节。
    注意,#pragma pack() 取消自定义对齐方式,恢复默认方式,而push之后pop是回到push指令之前的对齐方式。
    eg:

    #include <stdio.h>
    #pragma   pack(2) 
    #pragma pack(push) 
    #pragma   pack(4) 
    struct CC {
        double d;
        char b;
        int a;
        short c;
    };
     
    #pragma   pack(1) 
    struct BB{
        double d;
        char b;
        int a;
        short c;
    };
    #pragma pack()
    struct AA{
        double d;
        char b;
        int a;
        short c;
    };
    int main(void)
    {
        
        printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
        return 0;
    }

    只把pop改成pack()打印如下:
    在这里插入图片描述
    最后回到的不是2字节对齐,而是默认的8字节对齐。

    延伸

    还有延伸点:
    在这里插入图片描述
    上图红色处等价于它下面的两句。

    语法:

    #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的数值,以字节为单位;

    另外:

    __attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
    __attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐

    参考

    参考原文:https://www.cnblogs.com/yangguang-it/p/7392726.html

    展开全文
  • 前言 我们都知道结构体内存对齐字节可以通过#pragma pack(n)的方式指定。...#pragma pack(1) struct AA{ double a; int b; short c; char d; char e; char f; } #pragma pack() struct BB{ double a; int b

    前言

    我们都知道结构体内存对齐字节可以通过#pragma pack(n)的方式指定。
    但是,有时候我想这个结构体用1字节对齐,下一个结构体用4字节对齐,那怎么办呢?

    测试

    #include <stdio.h>
    
    #pragma pack(1)
    struct AA{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    }
    #pragma pack() 
    struct BB{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    }
    int main(void) { 
    	printf("%u\n%u\n",sizeof(struct AA),sizeof(struct BB));
    	return 0;
    }
    

    结果是:结果1
    这说明了,在强制1字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。
    2.

    #include <stdio.h>
    //#pragma pack(push)
    #pragma pack(1)
    struct AA{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    }
    #pragma pack(pop) 
    struct BB{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    }
    int main(void) { 
    	printf("%u\n%u\n",sizeof(struct AA),sizeof(struct BB));
    	return 0;
    }
    

    结果是:
    结果
    那如果加上#pragmatic pack(push)后呢
    结果

    总结

    #pragma pack(push):英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。

    #pragma pack(pop):英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。

    push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。

    这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4)

    struct{
    }

    #pragma pack() ;
    也可以使用:
    #pragma pack(push)
    #pragma pack(4)

    struct{
    }

    #pragma pack(pop)

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

    struct{
    }

    #pragma pack(pop)

    这是给编译器用的参数设置,有关结构体字节对齐方式的设置大概是指把原来对齐方式设置压栈,并设新的设置为4

    例子

    #include <stdio.h>
    //#pragma pack(push)
    #pragma pack(push,2)
    struct AA{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    };
    #pragma pack(1)
    struct BB{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    };
    #pragma pack(pop)
    struct CC{
    	double a;
    	int b;
        short c;
        char d;
        char e;
        char f;
    };
    int main(void) { 
    	printf("%u\n%u\n%u\n",
    		sizeof(struct AA), sizeof(struct BB), sizeof(struct CC));
    	return 0;
    }
    

    结果是:结果
    分析:第一个结构体AA是按照2字节对齐,第二个结构体是按照1字节对齐的,最后一个则恢复为8字节对齐。

    展开全文
  •      #pragma pack(n) 解释一: 每个特定平台上的编译器都有自己的...程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。  规则:  1、数据...
  •  #pragma pack(n) ...每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐...程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。  
  • C #pragma pack(push,1) #pragma pack(pop)解析

    千次阅读 2018-08-14 17:39:48
    #pragma pack( push, 1 ) #else #pragma pack(1) #endif Typedef struct { } #ifdef _WIN32 #pargma pack(pop) #else #pragma pack() #endif   二、对 #pragma pack()的理解 在程序中,我们有时候在定义...
  • #pragma pack详解

    2021-04-13 16:21:01
    计算机中都是以字节划分内存空间,通常编译器会为我们选择适合目标平台的对齐策略,但是有时候也带了一些麻烦,要自定义变量的对齐策略我们就需要用到#pragma pack。 应用场景 百度百科里提到一个典型的应用场景:...
  • #pragma pack 用法详解

    2019-06-21 20:17:49
    pack 为 struct, union 和 class 等的成员对齐指定字节边界. 与编译选项(属性 -> 配置属性 -> C/C++ ->...1. #pragma pack(show) 以警告信息的形式显示当前字节对齐的值. 2. #pragma pac...
  • #pragma pack的使用

    2020-02-04 21:10:26
    编译器会根据操作系统及编译环境来自动设定结构体的内存对齐的默认字节,但是在实际开发中,有时候考虑到实际内存,会有将结构体设置为1字节对齐(不对齐)的需求,这个时候就要借助C/C++编译指令#pragma pack(),这...
  • C++ #pragma pack(push,1)

    2021-07-21 20:06:22
    1. 机器的位数 计算机一次能处理数据的最大位数称为该机器的位数,位数跟电脑的CPU有关。 64位的机器一次最多从内存中读取8字节 32位的机器一次最多从内存中读取4字节 2. 对齐系数 每个特定平台上的编译器都有自己的...
  • 1 引子 ... 在程序中,有的时候我们定义结构体的时候,要用#pragma pack(push,1) & #pragma pack(pop)类似代码将结构体包起来。 一般形式如下: #pragma pack(push,1); struct A {   } ;
  • 数据在计算机内存储涉及到内存字节对齐机制,它是为了...#pragma pack(n) #pragma pack(n) 其作用是指定编译器的字节对齐参数为n 用法 #pragma pack(n) 代码 #pragma pack() 代表在这之间的代码数据按n字节对齐进...
  • 1 引子 在程序中,有的时候我们定义结构体的时候,要用#pragma pack(push,1) &amp; #pragma pack(pop)类似代码将结构体包起来。一般形式如下:#pragma pack(push,1); struct A{ } ;#pragma pack(pop);这么...
  • #pragma pack(1) 使结构体按1字节方式对齐例如:struct sample{char a;double b;};若不用#pragma pack(1)和#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐...
  • 编译器会根据操作系统及编译环境来自动设定结构体的内存对齐的默认字节,但是在实际开发中,有时候考虑到实际内存,会有将结构体设置为1字节对齐(不对齐)的需求,这个时候就要借助C/C编译指令#pragma pack(),这个...
  •  #pragma pack(n) // 强制让编译器内存对齐为:1字节对齐 /* 必须在结构体定义之前使用 */  // 在这儿定义多个结构体 //   #pragma pack(pop) /* 恢复先前的pack设置 */ 如: #pragma pac...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,186
精华内容 9,274
关键字:

#pragma pack(1)