文档章节

关于结构体内存对齐方式的总结(#pragma pack()和alignas())

o
 osc_odyg6b92
发布于 2018/07/13 16:33
字数 1439
阅读 12
收藏 0
c++

行业解决方案、产品招募中!想赚钱就来传!>>>

最近闲来无事,翻阅msdn,在预编译指令中,翻阅到#pragma pack这个预处理指令,这个预处理指令为结构体内存对齐指令,偶然发现还有另外的内存对齐指令aligns(C++11),__declspec(align(#))(Microsoft专用),遂去探究两者之间的不同点。

1、#pragma pack

这个指令为预处理指令,所谓与处理指令执行在程序的预处理阶段,该指令对应着编译选项/Zp,可以在vs的工程属性中设置编译选项的内存对齐,也可以利用预处理指令来设置。

#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n ) 

预处理指令的用法如上,其中必选参数n为内存对齐值,有效值为1、4、8、16,默认值为8。可选参数中,show代表右警告消息显示当前的内存对齐值,push | pop 二者选其一,代表将当前的内存对齐值入、出栈。identifier跟随push | pop一同出入栈,作为表示使用。

2、aligns、__declspec(align(#))

aligns和alignof为c++标准的类型说明和运算符,其中aligns为内存对齐类型符,alignof为返回内存对齐值得运算符。对应还有Microsoft的msvc专用的__alignof()和__declspec(align(#))也可以达到同样的的效果。

__declspec(align(#))和aligns(#)中#为对齐值,可选的对齐值为2、4、8、16、32、64

3、区别

同样是对齐操作,两种不同的对齐操作有什么区别呢。

字面上,一个是预处理指令,另一个是类型说明符。

在相应的结构体内存对齐上,也存在差别。

所谓的内存对齐指的是变量分配到要求的内存地址上,这个地址必须是对齐值的整数倍,例如int型变量,默认的对齐值为数据长度,也就是4,分配到内存地址0x0001103F,该地址模上内存对齐值,也就是4。1103F%4=3,所以将int型变量分配到0x00011042上,该地址为对齐值得整数倍。

定义一个结构体,结构体内存对齐值为内存存储变量的最大默认对齐值

struct   MyStruct
    {
        char member;
        int a;

    }mystruct;

    sizeof(mystruct) = 8,alignof(MyStruct) = 4

通过计算可以看出,结构体的对齐值为4,内存占用为8。结构体遵循内存对齐规则,结构体内部变量也遵循对齐规则,其中char偏移量0,int偏移量为4,两变量之间填充3字节数据。

  • #pragma pack(1),再次计算sizeof和alignof

    sizeof(mystruct) = 5;alignof(MyStruct) = 1

    可以看出,预处理指令要求的内存对齐为1设置生效了。

  • __declspec(align(2)),最小对齐值,再次计算sizeof和alignof

    __declspec(align(2))
     struct   MyStruct
     {
         char member;
         int a;

     }mystruct;

    sizeof(mystruct) = 8;alignof(MyStruct) = 4

    设置内存对齐失败了。

    •  用c++11标准再试试,align(2) 
struct  alignas(2)   MyStruct
     {
         char member;
         int a;

     }mystruct;

这下vs直接报错,'MyStruct': Alignment specifier is less than actual alignment (4), and will be ignored

    通过这个报错,可以看出,类型说明符形式的内存对齐要求最小的对齐值为结构体的对齐默认值,也就是内存变量的最大对齐  值。

  • __declspec(align(8)),计算sizeof和alignof
__declspec(align(8))  struct   MyStruct
     {
         char member;
         int a;
     }mystruct;
     sizeof(mystruct) = 8;alignof(MyStruct) = 8

     struct alignas(8)  MyStruct
     {
         char member;
         int a;

     }mystruct;

  sizeof(mystruct) = 8;alignof(MyStruct) = 8

    其中char偏移为0,int 的偏移为4,中间填充3字节数据

  • 将aligns(8)添加到结构体内部变量,设置内部变量的对齐值
struct  MyStruct
     {
        alignas(8) char member;
        alignas(8) int a;
     }mystruct;

    sizeof(mystruct) = 16;alignof(MyStruct) = 8

此时可以看出,结构体对齐值为内部变量最大对齐值8,其中char变量对齐值为8,偏移量0,int对齐值为8,偏移量为8,中间   填充7字节数据,结尾填充4字节数据。可见 alignas()对于修饰的变量有效

  • aligna(16)
struct alignas(16) MyStruct
     {
        char member;  
        int a;  
     }mystruct;

     sizeof(mystruct) = 16;alignof(MyStruct) = 16

  sizeof(mystruct) = 16;alignof(MyStruct) = 16

    其中char偏移量0,int偏移量为4,中间填充3字节数据,结尾填充8字节数据

  • #pragma pack(16)

     sizeof(mystruct) = 8;alignof(MyStruct) = 4

    可以看出通过预编译指令设置对齐失效了。

aligna(16)和#pragma(1)
    #pragma pack(1)
     struct alignas(8) MyStruct
     {
        char member;  
        int a;  
     }mystruct;

     sizeof(mystruct) = 8;alignof(MyStruct) = 8

    设置了预编译指令和alignas(),遵循alignas()

4、总结

我们可以通过两种方式来设置对齐,分别是#pragam pack()和alignas()/declspce(align(#)) 
对于#pragma pack()我们可以设置全局对齐方式,结构体和结构体内部变量都将遵循设置的对齐参数;而alignas()对修饰的单个变量是,对齐参数有效,例:alignas()修饰结构体变量,那么结构体变量遵循该对齐参数,内部变量遵循默认的对齐参数,以上对齐方式均是对结构体变量起作用,对于数据区的其他变量不管如何设置对齐方式,还会按照默认的字节来对齐。
#pragma pack()这种对齐参数设置有最大上限,最大设置为其默认对齐参数;alignas()/declspce(align(#))这种对齐方式存在最小下限,最小下限为默认对齐参数。
对于设置两种对齐方式,优先遵循alignas()这种对齐方式。
结构体的默认对齐方式为4byte,最终的结构体对齐方式与结构体内所占最大空间的项的对齐方式一致
结构体所占空间一定为对齐参数的整数倍,也就意味着结构内部可能会存在填充的字节

o
粉丝 1
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2
集群存储系统--YFS

YFS集群存储系统由多个元数据服务器(MDS)、多个块数据服务器(CDS)和多个客户端(client)互联组成集群; 数据被分成64M固定大小的数据块(Chunk),每个数据块在CDS本地以常规文件的形式...

匿名
2013/02/19
1.7K
0
tiny php template--TPT

关于TPT TPT是php实现的用于模板解析小工具,全部实现仅仅60行代码。 配置 DIRCOMPILED和DIRTEMPLATE,分别表示模版编译目录和模版文件目录: define('DIRCOMPILED','/compileddiy');define(......

红猪-侠
2013/03/03
1K
1
Top Aligning Label

实现文字顶部对齐(Top Alignment)的UILabel。原有的 UILabel 中的文字对齐方式不能顶部对齐,只能中部以及左右对齐。这份代码实现的 MCTopAligningLabel 类可将文字顶部对齐。在下面截图中...

匿名
2013/01/11
392
0
建站引擎--PHPMyWind

PHPMyWind 是基于PHP+MySQL开发符合W3C标准的建站引擎。它将带给人们一系列高效的,成熟的企业网站建设解决方案,让您的信息以更健康的形式高速传递给需要的它的人们,同时让您感受通过PHPMy...

匿名
2013/01/14
4.4K
1

没有更多内容

加载失败,请刷新页面

加载更多

如何在SQL Server中将多行文本合并为单个文本字符串?

问题: Consider a database table holding names, with three rows: 考虑一个包含名称的数据库表,该表具有三行: PeterPaulMary Is there an easy way to turn this into a single str......

富含淀粉
30分钟前
9
0
在JavaScript中生成特定范围内的随机整数? - Generating random whole numbers in JavaScript in a specific range?

问题: 如何可以生成两个指定的变量之间的随机整数在JavaScript中,例如x = 4和y = 8将输出任何的4, 5, 6, 7, 8 ? 解决方案: 参考一: https://stackoom.com/question/6PRz/在JavaScript中...

fyin1314
今天
8
0
Vim清除最后一个搜索突出显示 - Vim clear last search highlighting

问题: Want to improve this post? 想要改善这篇文章吗? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. 提供此问题......

技术盛宴
今天
23
0
马化腾每天刷 Leetcode?代码你打算写到几岁?

本文作者:o****0 前几天,一张未证真伪的截图流传,图中显示马化腾几乎每天都会在 Leetcode 上提交代码。 截图还贴出一个 Leetcode 账户地址。该地址的头像已从马化腾的照片换成腾讯 logo,...

百度开发者中心
前天
13
0
滴滴 3000+ Kylin Cube 背后的实践经验揭秘

本次分享主要有三个部分:Kylin 在滴滴的整体应用、架构的实践经验、滴滴全局字典最新版本的实现以及 Kylin 最新实时 OLAP 探索经验分享。 Kylin 在滴滴的应用&架构 Kylin 在滴滴的三类应用场...

浪尖聊大数据
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部