c语言变量的初始化和赋值的区别

原理

顺着这个思路想了一下,为什么C语言的全局变量(global)就算不赋值会被自动初始化位默认值,但是局部变量(local)不会呢? 学习了一下C语言的内存布局结构,然后自己验证了一下然后明白了这个原因。

首先我们得知道C语言的内存布局结构,这篇文章 Memory layout of c program 讲的非常详细。这里列出我要用到的部分,首先看结构(图片来自这篇文章):

从这篇文章里面我明白了两点:

  • 全局变量是存放在data段内存的。data段分为uninitialized data(bss)段和initalized data,未初始化的变量是放在bss段的,这部分内存存放的变量是会被自动初始化的(这是C语言的特性)
  • 局部变量是存放在stack段的。这部分内存是被runtime时期动态分配的。(其实局部变量在代码编译之后就是一个地址,接下来会演示出来)

明白了这两点,那我通过一个demo来验证一下是否在内存中真的是这个样子。

//test_c_variable_init.c

#include <stdio.h>

int global_var;

int main()
{
    int local_var;
    
    local_var = local_var + 3;
        
    printf("global_var: %d & local_var: %d \n", global_var, local_var);
    
    return 0;
}

利用demo里面声明的一个全局变量(global_var)和局部变量(local_var)来验证现在的问题。(对local_var加常量3的操作仅仅是为了能够快速定位local_var在反编译代码中的位置)

首先可以通过linux的size命令查看总的内存分布

编译test_c_variable_init.c文件

gcc -o test_c_variable_init test_c_variable_init.c

得到可执行文件test_c_variable_init,现在可以查看到这个可执行文件的内存分布:

然后我们在test_c_variable_init.c中增加一个全局变量:

int global_var2;

按照之前的步骤我们再次查看重新编译的文件的内存分布:

可以看到bss段增加了4kb,这个大小就是我们增加的global_var2变量的大小。按照同样的方式增加local_var2我们会发现data和bss段都不会增加。这样可依初步确定上面列出的两点结论了。

然后我们通过查看反编译代码直接来查看变量在编译之后的位置,这样就明确之前的两点结论。

objdump -D test_c_variable_init > test_c_variable_init.d

我们把反编译之后的代码重定向到test_c_variable_init.d文件,然后我们查看下这个文件,其中有两个地方可以让我们得到想要的答案。

这是反编译之后的main函数:

可以看到347行的 $0xc ,之前我列出demo的时候为local_var特地添加了一个加常量3的操作,通过这个操作我可以很快定位到了$0xc 就是对应的local_var变量了, $0x3 就是常量3(addl就是汇编里面的加运算)。这里证明了local_var是分配在stack区的。此外我们注意到 0x804a020 这个地址其实就是global_var变量了,跳转到这个地址

可以很清楚的看到 0x804a020 就是global_var并且存放在bss段的。

这样我们就验证了上面的两点结论了,也知道了为什么未初始化的全局变量会被自动初始化位默认值,局部变量不会被初始化了。







一般变量看不出什么区别,对于静态变量就很明显了,如:


int func()
{
static int a = 10; //初始化
static int b;
b = 10; //赋值
a++;
b++;
printf("%d\n", a); //第一次调用函数func,a 的值为 11,第二次调用时为 12,……
printf("%d\n", b); //第一次调用函数func,b 的值为 11,第二次调用时为 11,……
}
从上例可以看出,静态变量只初始化一次,所以 a 的值会随调用的次数递增;而 b 由于重新赋值,所以他的值始终是 11。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页