美文网首页嵌入式linux简书收藏--C语言嵌入式
C语言数据起始地址对齐方式(续)

C语言数据起始地址对齐方式(续)

作者: 爪爪熊 | 来源:发表于2016-10-26 17:55 被阅读191次

    开篇废话

    这几天一直忙着积累知识,还没有来得及总结呢,前些日子讲述了一种在C语言环境中设置数组的对齐的方式,但是那个方式的演示是在IAR 的编程环境中给予支持的,对于icf文件(连接文件)在gcc中叫做ld文件,很多人都没有接触过,更不知道如何去设置段的方式进行对齐。

    正篇

    还是上篇中讲述的那个需求,在最近的某个月黑风高的夜晚,睡觉之前的我突发奇想,想到一种另类的解决办法,也就是套用结构体的办法去实现数组的首地址对齐方式。

    需求:实现一个大数组 array_a[3874]的首地址在一个4字节或者8字节对齐的地址上。

    首先,构造一个简单的结构体:

    struct test
    {
        char a[3874];
        int  b ;
    };
    

    使用C99/C++中支持的静态初始化结构体的办法进行赋值:

    static struct test test1 = {
        .a[3874] = {1,2,3,4...},      //C++   C99以上才支持这种赋值方式。
    };
    

    这样子定义的数组a[3874]的首地址就是位于一个4字节对齐的地址上的。

    如果要8字节对齐呢?将结构体改为如下,初始化的方式同上即可。

    struct test
    {
        char a[3874];
        double b ;
    };
    

    为啥这样子就可以了呢?
    是这样子的:

    解释如下

    这里使用了一种结构体字节对齐来解决了数组首地址对齐的问题:因为结构体字节对齐满足三个准则

    引用自cnblogs上一位大神(clover_toeic)的博客 文章名为《C语言字节对齐问题详解
    》这里不便提供具体链接,感兴趣的朋友自行百度。

    1. 结构体变量的首地址能够被最宽基本类型成员大小所整除;
    2. 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的的整数倍,如有需要编译器会在成员之间加上填充字节;
    3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员加上填充字节;

    上述解决办法正是使用了第一个原则,比如第二个结构体中:

    struct test 
    {
        char a[3874];
        double b ;
    };
    

    可以看出该结构体中最宽的基本类型成员是double,在32位机器中占用64bit也就是8Byte,所以我们的结构体首部地址存在于一个8Byte对齐的地址上,而成员中的第一个 char a[3874],正好是从结构体中首地址开始占用的,a[0]的地址就是结构体的首地址;

    总结,此方法优于之前提出的在链接文件中划分块的方式进行对齐,因为这种方式不依赖编译器,是一种通用的方法。

    感谢

    如果我的文章有哪里有错的地方,劳烦读者指出哈。如果觉得我的文章对您有用,那就麻烦回复我一下,表示有用。如果确实很有用,就请点一个喜欢,谢谢啦。

    相关文章

      网友评论

      本文标题:C语言数据起始地址对齐方式(续)

      本文链接:https://www.haomeiwen.com/subject/dbxjuttx.html