c语言内存分布之数据段
不管我们以后是自己写代码还是读别人的代码,都应该想想这个变量默认存储的位置。在我们以后的嵌入式开发中,技巧性的代码越来越多的时候,我们可能把某一些代码放在一段。我们可以通过修改变量或者代码默认放置的段,让它被放到其它的段中。我们也可以自己定义一个新的段。
随着运行,栈空间是随时会变化的。栈空间临时的去存储一些变量,当我们进入一个函数,系统就会在栈空间去分配一片内存去保存这个函数里面所有的变量。当函数执行完之后,这一片内存的数据就被销毁了。当我们在初学的时候,就千万不要犯把局部变量给别人的错误。

全局的数据空间和只读数据段,代码段都是在运行之前就已经分配好了的。所以我们在打印信息的时候应该尽量不要使用太多的字符串,否则容易导致程序的可执行文件很大。所以我们在最后发布程序的release版本里面去除了我们一些调试用的信息。
测试代码如下
我们在main函数外面申请了一个全局变量b,但是我们并没有为这个b赋初始值。它仅仅只是为这个变量圈出了一块内存,里面有为全局变量自动初始化的0值。

运行结果如下
上面的结果是没有变量b的结果,下面是添加全局变量b的结果。bss段就是未初始化的全局变量存储的段,上面的全局变量b就在这个段中分配了四个字节(尽管系统已经将它初始化为0,但是并不是我们初始化的)。

测试代码如下
我们只是将未初始化的变量b将它初始化了。

运行结果如下
可以看到,在未初始化的字段里面少了四个字节,而在已初始化的字段里面多了四个字节。所以我们也将date称做全局初始化数据空间,bss称做全局未初始化数据空间。局部的变量不管有没有初始化都是存储在栈上。

Static关键字声明变量的时候,系统就会将它认为是一个全局变量,即使它在函数内部声明。此时,它分配的地址也就在全局的数据空间。
测试代码如下

运行结果如下
这就是声明变量a为静态数据前后的结果,此时分配的段为全局未初始化数据空间,现在它不在栈中,那么就不会随着栈的弹出而被销毁了。静态数据段的消失是在整个程序都消失之后才会消失。

测试代码如下
我们在两个函数里面声明了两个一样的变量a,虽然它们是一样的名字,但是它们在系统中的访问却是不一样的,fun函数里面的a++调用的是该函数里面的。Main函数也是对应的。

运行结果如下
这是添加一个fun函数前后的结果,编译器并没有对两个全局变量报错,它将fun函数里面的静态变量a放到了data段中。虽然它们是一样的变量名,但是在编译器中,它们有不一样的后缀。

我们可以通过nm build查看静态的数据段,前面为地址,两个变量的后缀是不一样的。

Static相当于全局的数据空间的一个显示分配的符号,它可以更改局部数据的默认存储段,虽然它们的访问依然是局部的,但是存储位置已经在全局数据段中了。