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


    强调一点:


    #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。

  • 相关阅读:
    单例模式
    HashSet、LinkedHashSet、SortedSet、TreeSet
    ArrayList、LinkedList、CopyOnWriteArrayList
    HashMap、Hashtable、LinkedHashMap
    andrew ng machine learning week8 非监督学习
    andrew ng machine learning week7 支持向量机
    andrew ng machine learning week6 机器学习算法理论
    andrew ng machine learning week5 神经网络
    andrew ng machine learning week4 神经网络
    vue组件监听属性变化watch方法报[Vue warn]: Method "watch" has type "object" in the component definition. Did you reference the function correctly?
  • 原文地址:https://www.cnblogs.com/lidabo/p/3190793.html
Copyright © 2020-2023  润新知