引言
在我们学习嵌入式的时候,可能会接触到各种平台,那么我们的代码也有可能在不同的平台上运行。那么我们如果没有约定的一套规则的话,我们定义的一些类型去到其他的平台可能就会出现问题(比如操作系统Linux、Bootloader等系统型的软件,它们的使命就是应该要在不同平台中运行)。那么,这个时候我们就应该要了解跨平台的嵌入式程序,需要注意什么地方:
那么,有接触过项目开发的朋友,肯定也会看到过例程,或者别人的代码中的头文件都会这样数据类型的封装:
一、确保变量的大小固定(字节数大小)
以下面自己编写的程序、以及A平台、B平台为例子:
- A平台、B平台不同的类型所定义的字节数并不相同。如果我们自己编写的代码继续使用
int a
来定义的话,是不清楚a所被定义的字节数的,那么一旦程序在A平台上运行,就会导致崩溃。因此,这就是为什么很多程序都是使用int32_t
这种方法来定义变量。 - 当程序在A平台上面运行时,A平台使用了typedef的方法定义了
long int32_t
来表示,在A平台中,long类型定义的变量是占用4个字节的,那么传输过去A平台的a,将会变成long a
- 当程序在B平台上运行,同理可得:
int a
二、确保变量的相对位置固定(地址对齐)
什么是地址对齐?
首先补一下知识点:一个32位的系统的运作原理:
32位系统:指处理器拥有每次存储32位(4bytes)的数据。
假设,有一个32位的系统,现在要处理一个int a 为4个字节的数据,如果没有规则去限制这个a,那么这个a有可能是这样存入内存中:
- a在内存中的地址是连续的,可是CPU是32位,也就是每次处理4个字节的数据(一个红圈),那么针对以上情况,CPU的反应有两种:
1.不工作
2.降低效率,两次存储处理该变量。
以上的这种情况就是:地址不对齐情况
因此,我们要规定一个规则(地址对齐),告诉计算机要让a以下面这种方式去放入内存,才能让CPU高效率工作:
此时,a的地址满足条件:&a = 4*N 即可!
问题深入:
我们刚刚看完上面一个简单的例子,下面就应该对地址对齐的问题进行深入探讨。我们以上面的例子:&a=4*N 我们将这个4看作一个m值r然后来探讨下面几个类型的m值:
struct node
{
char a; 字节数为1
int b; 字节数为4
short c; 字节数为2
double d; 字节数为8
}
我们借助刚刚上面的例子可以推敲出这四个类型的m值:
这里以比较难理解的double类型为解释:
&d = 4 * N
N=0: &d=0
N=1: &d=4
N=2: &d =8
虽然说m值与byte有关,但是这里的m只需要4就可以了,如果为8的话就不合理,可以自己去画画看。
因此,控制m值成为了地址对齐的条件
第二个需要掌握的是系统计算这个包含abcd类型的结构体的大小:
我们通过画图,可以看到占用的是20
那么我们也可以通过代码来输出验证一下:
- 通过上面的图示,也看到了系统内存在存储char类型,short类型的时候,都在后面补零,而不是使用继续填充下一个类型的方法。那么这就是隐藏在系统中的地址对齐规则。
- 隐藏在里面的地址对齐还有对整个结构体的对齐规则:
我们可以看到系统首先存储的是char类型的a,那么a占用的字节是1,m值也是等于1。那么按照道理来说,a可以存放在内存的任何地方,但是为什么就是按照图示的位置存储呢?
这里就衍生出了,结构体Node的m值。结构体Node也是变量,其他,系统也对它要求地址对齐,因此它也有一个m值:m=4(取结构体变量中m值最大的)。
因此,a的地址位置就受到了结构体m值的约束。 - m值的作用:
1.规定起始地址为m的整数倍。例如:如果结构体的大小为4,那么该结构体的大小一定为4的整数倍,若不满,则补零填满。
2.变量的大小也为m的整数倍。
使用attribute固定m值
在定义变量时,使用__attribute__((aligned(m值)))
来固定m值:
那么,如果将代码更改为上图,我们的结构体占用的大小为多少呢?
- 存a:黑色阴影部分。
- 存c:蓝色阴影部分,补一个零。
- 存b:b的m值被更改为64,因此,存完4个字节后,在后面补60个零为64字节。
- 存d:存入8个字节。
- 52个零的由来:结构体node的m值为:64,可是现在所有加起来只占76字节。那么我们的结构体的m值为64,那么整个结构体的大小一定为64的倍数,因此,我们要往后面补零补足128个字节。
- 因此得到:8+60+8+52=128
我们看看程序的输出:
当你成功理解,并且算出这个128的大小后,恭喜你,你已经掌握了地址对齐了。在课堂中,可能老师都不会深入到这一点,但是当我们接触最底层,或者接触工作项目的时候就会遇到这一部分。这个时候,我们就能柔韧而解地完成项目。
最后再总结一次:编写跨平台的嵌入式程序要注意的地方
1.确保变量在不同平台的大小变化(字节数大小)
2.确保变量在不同平台的地址变化(使用m值确定地址位置,地址对齐)