关于内存对齐

事情的起因是这样的,我想在GNova写一个标识日期时间的类GDateTime,存储以下数据:

年份、月份、日期、星期、一年中的第几天、时、分钟、秒、毫秒。

并且可以针对以上数据进行操作。出于节省数据空间的考虑,每一项数据都尽量用最小容量的数据类型,比如年份使用guint16来存储,月份使用guint8来存储。这样以上所有的数据加在一起只占据了12个字节的数据空间。为了以后序列化的方便,我将所有的数据存储在一个字节数组中。

综合以上,我使用以下的一个数据结构来存储日期:

gbyte m_tDateTime[G_DATE_TIME_SIZE];

其中宏G_DATE_TIME_SIZE定义为一个值为12的整型字面值,这是一个能够容纳以上所有数据的最小尺寸。

当需要做日期的拷贝时,可以使用内存拷贝操作:

GMemCopy(m_tDateTime, dt.m_tDateTime, G_DATE_TIME_SIZE);

实际情况中,在执行以上代码时,系统会崩溃(vs2015):

Run-Time Check Failure #2 - Stack around the variable 'dt' was corrupted.

这是因为m_tDateTime这个字段的默认对齐规则是4个字节,而12这个数字,不满足对齐规则。在进行内存拷贝的时候,数组将以4个字节为单位进行拷贝,这样会造成内存越界。将12改为16,bug就消失了。

在C++11中,也可以通过alignas去设置对齐方式:

alignas(16) gbyte m_tDateTime[G_DATE_TIME_SIZE];

如上,由于改变了成员变量的对齐方式为16个字节,哪怕不把G_DATE_TIME_SIZE的值由12改成16,也能够正常运行,但此时也会带来存储空间的变化。

为了尽量减少存储空间的同时,还需要满足数据对齐方式,我们可以手工修改存储时的偏移量,最终修改情况如下:

共占据16个字节,其中有4个字节是用于内存对齐的无效数据,空间占据情况如下:

地址偏移(单位:字节) 说明
0 存储年份,占2个字节
2 存储月份,占1个字节
3 存储日期,占1个字节
4 存储星期,占1个字节
5 存储一年中的第几天,占2个字节
7 用于内存对齐的无效数据,占1个字节
8 存储小时,占1个字节
9 存储分钟,占1个字节
10 存储秒数,占1个字节
11 用于内存对齐的无效数据,占1个字节
12 存储毫秒数,占2个字节
14 用于内存对齐的无效数据,占2个字节

这样子设置存储规则,就可以使用原本值为4的内存对齐方式,而且为了保证获取数据时,不会因为内存对齐方式导致数据只能部分获取,在秒与毫秒之间,插入一个字节的无效数据。

在此基础上,GNova中的日期时间类GDateTime也能够正常、高效的运行了。

posted on 2017-02-28 11:02  乱世浮生  阅读(145)  评论(0)    收藏  举报

导航