本帖最后由 shibusha 于 2017-7-7 12:12 编辑
注:本帖仅讨论MDK V4.72未开启代码优化的情况。
MDK编译完程序后,MAP文件中可以看到各函数和变量的相关地址。其中变量分为两个大部分Local Symbols,和Global Symbols。
Local Symbols主要是相关静态局部变量,Global Symbols主要是全局变量。
让我们看一下下面的例子:
[mw_shl_code=c,true]
struct test
{
int ledd;
};
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3 = 0;
struct test testledd;
int main(void)
{
static u32 staticu32Test = 0;
static u8 staticTest = 0;
SystemInit(); //系统时钟等初始化
while(1)
{
gTest1 = 1;
gTest2 = 2;
gTest3 = 3;
testledd.ledd = 1;
staticu32Test = 1;
staticTest = 5;
};
}[/mw_shl_code]
编译后地址如下,可以看到未开起编译优化的情况下,MDK会自动补全不足4字节的变量地址。
例如gu8Test长度是1字节,再分配下一个4字节变量时,MDK会跳过中间三个字节的地址。
gTest1 0x20000018 Data 4 main.o(.data)
gTest2 0x2000001c Data 4 main.o(.data)
gu8Test 0x20000020 Data 1 main.o(.data)
gTest3 0x20000024 Data 4 main.o(.data)
testledd 0x2000002d Data 4 main.o(.data)
staticu32Test 0x20000028 Data 4 main.o(.data)
staticTest 0x2000002c Data 1 main.o(.data)
细心的同学可能发现上面地址有两个问题,
1. 未开启优化的前提下,将两个静态局部变量的地址,放在了全局变量testledd前面,没有按照创建的顺序编译
2. testledd的地址是奇数,正常理解,M3中,此结构体地址默认分配应该是4字节的倍数(int型变量)。
此时我们将上述代码稍作修改,将四个全局变量改为如下
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3;
此时编译的地址为:
gu8Test 0x20000020 Data 1 main.o(.data)
gTest3 0x2000002c Data 4 main.o(.data)
testledd 0x20000030 Data 4 main.o(.data)
可以看到,未初始化gTest3的情况下,MDK的分配顺序如下:
1. 初始化的全局变量
2. 初始化的静态局部变量(为初始化也一致)
3. 未初始化的全局变量&结构体。
此时发现与第一种情况对比,gTest3的地址是4字节对齐的,而第一种情况下结构体testledd是没有4字节对齐的。
那么问题来了,MDK在分配普通变量的时候,跳过了不足4字节的变量来保证地址对齐,为何在编译更为复杂的结构体,反而选择了“节省内存”呢?
并且这种情况下使用指针访问testledd还容易出错.
再看一个情况:
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3 = 0;
u8 gTest4;
struct test testledd;
gTest3 0x20000024 Data 4 main.o(.data)
gTest4 0x2000002d Data 1 main.o(.data)
testledd 0x2000002e Data 8 main.o(.data)
此时若初始化gTest4,结构体的地址又变回奇数。
以上是否可以理解为MDK编译后,在静态局部变量后的结构体,会被自动优化?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
一周热门 更多>