【理论实践】用alignas代替#pragma pack

来源:互联网 发布:天刀红唇萌妹捏脸数据 编辑:程序博客网 时间:2024/06/06 08:49

知识背景:

       字段对齐,使对象或成员的地址满足一定要求。4字节对齐就是地址都是4的整数倍,这个必须是2的N次方。

       为什么要对齐?一方面,如果4字节对齐了,对于128个内存空间,实际只有32个独立地址,相当于管理地址变少了,文件系统经常这么用,用少的寻址空间,管理更大的磁盘空间。另一方面,一些硬件设计上了,为了一些考虑,强制要求地址要符合指定规则。

       对齐有什么影响?最直接的影响就是占用内在大小变了,会影响sizeof,举例如下:

struct A{       int a;       char b;       int c;};
        sizeof(A)大小并不是4+1+4=9,而是12,4+4+4。

        为什么要改变对齐?强转之下,受对齐影响,不正确了。容易遇到的场景就是:收到网络字节流,消息头是结构化的,定义一个结构体,强转读取对应的字段


       怎么更改对齐大小?

       c++11之前,我们经常这么用

       #pragma pack(push)   //保存当前的对齐方式       #pragma pack(1)         //指定接下来,1字节对齐       //定义你的结构体       #pragma pop(pop)       //指定恢复保存的对齐方式


        明显这个相当暴力了,如果每个人都这么做,至少3行代码。为了省事,总容易有人不push和pop,直接改,某人就会在不知情的情况下,包含了这个头文件,进而受影响……

        于是,编译器突破规范,定义了扩展:__declspec(align(n))等,记住,是等,也就是各做各的,不统一,于是c++11火速规范化制定了这个标准:alignas 和alignof。

        a开头的关键字,排在最前面,有人会郁闷吧,总看到,却不知道是什么,我从误区开始,逐步解释一下。

        用法:alignas(t)  define;   t可以是个常量表达式,也可以是具体的大小,也可以是一个类型。 define是原本的定义语句,例如:

        alignas(int) int b;

        struct alignas(33) s

        {

                int a;

        };

        alignof(type),和sizeof非常类似,只是返回对应类型的对齐大小,例如:

         cout << alignof(s);           //返回s的对齐方式

         cout << alignof(s::a) ;      //返回s成员的对齐方式


理论实践

        知识讲完了,开始错误之路吧

        一、对齐不是2的N次方

struct alignas(3) A    //error: requested alignment is not a power of 2{        char a;        char b;        char c;        char d;};

        二、理解错了对齐对象

struct alignas(2) A{        char a;        char b;        char c;        char d;};if(sizeof(A) == 8)
       alignas修饰结构体时,不是对齐结构体每个成员,而是对齐结构体本身,所以大小不是4*2=8,则是4不变。如果再增加一个char成员,则大小6, 不是5。

       这样去理解结构体对齐:A对齐了,A+sizeof(A)是下一个A元素的地址,需要同样满足对齐,所以需要补空间1。


        三、对齐低于结构体成员最大对齐

struct alignas(2) A{        int a;        char b;};
        sizeof(A)不是6,而是8,因为a已经是4对齐了,所以b之后会补到8。   alignas(16)则大小是16。

         四、分析一下复杂的,就毕业了,sizeof(B)是多少?128

struct alignas(32) A{        int a;        alignas(8) char b;};struct B{        A a;        A b;        alignas(1) char c;        A d;};
          

          以后,再怀疑字节对齐时,请用alignof输出实际的对齐方式看看,不用再去打印内存或调试了。

原创粉丝点击