当前位置: > 华清远见教育科技集团 > 嵌入式学习 > 讲师博文 > 内存对齐问题总结
内存对齐问题总结
时间:2016-12-14作者:华清远见

内存对齐问题是嵌入式工程师都会遇到的问题,受学生的一道应聘笔试题的启发,今天做个内存对齐问题的总结。

先说为什么要内存对齐呢?看到一篇很好的文章,引用一下。

//www.ibm.com/developerworks/library/pa-dalign/

因为处理器读写数据,并不是以字节为单位,而是以块(2,4,8,16字节)为单位进行的。如果不进行对齐,那么本来只需要一次进行的访问,可能需要好几次才能完成,并且还要进行额外的合并或者数据分离。导致效率低下。更严重地,会因为cpu不允许访问unaligned address,就会报错,或者打开调试器或者dump core。所以一般编译器都会在编译时做相应的优化以保证程序运行时所有数据都是存储在'aligned address'上的,这就是内存对齐的由来。

我们学习的ARM架构中也有内存对齐的要求,ARM架构已被设计成快速又简单的32位存储器接口。每次存取只需一个存储周期,因此不能跨4字节边界存取。所有非对齐字和非对齐半字都是不允许的。非对齐地址将产生不可预测的/未定义的结果,默认用Data Abort异常来检测无效的非对齐数据存取。所以不注意内存对齐问题,轻则影响执行效率,增加内存开销,重则影响程序执行,甚至直接跑飞。

内存对齐的规则有以下几条 各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。

(1)成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。(按0起始位即可,看首地址位)

Char 偏移量必须为sizeof(char) 即1的倍数
        int 偏移量必须为sizeof(int) 即4的倍数
        long 偏移量必须为sizeof(long) 即4的倍数
        float 偏移量必须为sizeof(float)即4的倍数
        double 偏移量必须为sizeof(double)即8的倍数
        Short 偏移量必须为sizeof(short)即2的倍数

(2)为了确保结构的大小为结构的字节边界数(即该结构中占用大空间的类型所占用的字节数的倍数,所以为后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。

(3)结构中嵌套子结构,嵌入的子结构按拆分后基本类型处理,不考虑子结构整体。

(4)通过#pragma pack(n)指令来设定变量以n字节对齐方式。

n字节对齐就是说变量存放的起始地址的偏移量有两种情况:

a、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式。

b、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

其核心就是设定变量和总体的对齐的上限。变量格式大于n,按n处理,n的单位字节。

下面我们对照规则看个例子:

执行结果:

我们来分析下:

(1) 对于结构体t

struct t_struct
        {
     &nbnbsp;          char a; //本身占1个字节,没有对齐问题
                int d; //本身占4个字节,内存对齐补3个字节
                float c; //本身占4个字节,没有对齐问题
                char b; //本身占1个字节,没有对齐问题
        }t; //结构体内部1+3+4+4+1 =13
        //结构体大单元4个字节,内存补齐3个字节,
        // 整体大小13+3=16

(2) 对于结构体c的分析方法同(1)

(3) 对于结构体s,将内嵌的结构体b展开

struct s_struct
        {
                char d;
                // struct c_struct b;
                {
                        int d;
                        float c
                }
                char a ;
        }s;

展开后的分析方法同(1)。

发表评论
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)