开篇废话
这几天一直忙着积累知识,还没有来得及总结呢,前些日子讲述了一种在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语言字节对齐问题详解
》这里不便提供具体链接,感兴趣的朋友自行百度。
- 结构体变量的首地址能够被最宽基本类型成员大小所整除;
- 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的的整数倍,如有需要编译器会在成员之间加上填充字节;
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员加上填充字节;
上述解决办法正是使用了第一个原则,比如第二个结构体中:
struct test
{
char a[3874];
double b ;
};
可以看出该结构体中最宽的基本类型成员是double,在32位机器中占用64bit也就是8Byte,所以我们的结构体首部地址存在于一个8Byte对齐的地址上,而成员中的第一个 char a[3874],正好是从结构体中首地址开始占用的,a[0]的地址就是结构体的首地址;
总结,此方法优于之前提出的在链接文件中划分块的方式进行对齐,因为这种方式不依赖编译器,是一种通用的方法。
感谢
如果我的文章有哪里有错的地方,劳烦读者指出哈。如果觉得我的文章对您有用,那就麻烦回复我一下,表示有用。如果确实很有用,就请点一个喜欢,谢谢啦。