前言
这也是一个老生常谈的问题
呵呵 不同类型的变量 都存放在哪些地方
这里主要列一下 常见的几种变量
初始化过的静态变量, 未初始化的静态变量, 初始化过的局部变量, 为初始化过的局部变量, malloc 分配的变量
这里 来探究一下 它们具体存放的地方, 以及一些 特征
测试用例
测试用例如下, 主要是 上述一些 变量的定义 和 简单使用
#include "stdio.h"
void beforeFoo();
void foo();
int main() {
beforeFoo();
foo();
foo();
foo();
return 0;
}
void beforeFoo() {
int x = 10043;
int y = x + 12;
int z = y + 13;
int w = z + 14;
int d = w + 15;
printf(" x = %d, y = %d, z = %d, w = %d, d = %d \n", x, y, z, w, d);
printf(" x = 0x%x, y = 0x%x, z = 0x%x, w = 0x%x, d = 0x%x \n", &x, &y, &z, &w, &d);
printf("-------------------------------------------------------------------\n");
}
void foo() {
static int varInStaticInited = 3;
static int varInStaticUnInited;
int varInStackInited = 4;
int varInStackUnInited;
int *varInMalloc = (int *) malloc(10);
varInStaticInited++;
varInStaticUnInited++;
varInStackInited++;
varInStackUnInited++;
*varInMalloc = 99;
printf(" varInStaticInited = %d, varInStaticUnInited = %d, varInStackInited = %d, varInStackUnInited = %d, varInMalloc = %d \n",
varInStaticInited, varInStaticUnInited, varInStackInited, varInStackUnInited, *varInMalloc);
printf(" varInStaticInited = 0x%x, varInStaticUnInited = 0x%x, varInStackInited = 0x%x, varInStackUnInited = 0x%x, varInMalloc = 0x%x \n",
&varInStaticInited, &varInStaticUnInited, &varInStackInited, &varInStackUnInited, varInMalloc);
printf("-------------------------------------------------------------------\n");
}
编译执行结果如下
可以看出的是 一些如下结论, 从各个变量的值来看
varInStaticInited 的数据初始化为3, 一直在累增
varInStaticUnInited 初始化为默认的0, 一直在累增
varInStackInited 初始化为5, 每进入 foo 函数, 会初始化一次
varInStackUnInited 初始化为未知值, 每进入 foo 函数 在原来的未知值的基础上面加1
varInMalloc 初始化为 99, 每进入 foo 函数, 会初始化一次
从各个变量的地址来看
varInStaticInited 和 varInStaticUnInited 是放在 Test21DiffVars 的某个段, 从这里看着 貌似是相邻的, 可能在同一个段
varInStackInited, varInStackUnInited 相邻, 均是在当前 foo 函数的栈帧空间
varInMalloc 是分配在 heap, 由 brk 系统调用进行分配空间, malloc 二次管理
root@ubuntu:~/Desktop/linux/HelloWorld# ./Test21DiffVars
x = 10043, y = 10055, z = 10068, w = 10082, d = 10097
x = 0xdc273d54, y = 0xdc273d58, z = 0xdc273d5c, w = 0xdc273d60, d = 0xdc273d64
-------------------------------------------------------------------
varInStaticInited = 4, varInStaticUnInited = 1, varInStackInited = 5, varInStackUnInited = 10069, varInMalloc = 99
varInStaticInited = 0x601050, varInStaticUnInited = 0x601058, varInStackInited = 0xdc273d58, varInStackUnInited = 0xdc273d5c, varInMalloc = 0x20f8420
-------------------------------------------------------------------
varInStaticInited = 5, varInStaticUnInited = 2, varInStackInited = 5, varInStackUnInited = 10070, varInMalloc = 99
varInStaticInited = 0x601050, varInStaticUnInited = 0x601058, varInStackInited = 0xdc273d58, varInStackUnInited = 0xdc273d5c, varInMalloc = 0x20f8440
-------------------------------------------------------------------
varInStaticInited = 6, varInStaticUnInited = 3, varInStackInited = 5, varInStackUnInited = 10071, varInMalloc = 99
varInStaticInited = 0x601050, varInStaticUnInited = 0x601058, varInStackInited = 0xdc273d58, varInStackUnInited = 0xdc273d5c, varInMalloc = 0x20f8460
-------------------------------------------------------------------
程序组成
我们先来概览一下 整个程序上的结构
main 函数如下, 依次调用了 beforeFoo, 然后 调用了三次 foo
beforeFoo 如下
bp-8 为一个暂存的局部变量
bp-0x1c 为 x, bp–0x18 为 y, bp–0x 14 为 z, bp–0x10 为 w, bp –0xc 为 d
然后函数调用, 是从右到左依次入栈, 然后调用 printf
foo 如下
bp-8 为一个暂存的局部变量
bp-18 为 varInStackInited, bp-14 为 varInStackUnInited, bp-10 为 varInMalloc
然后通过偏移操作 varInStaticInited, varInStaticUnInited
各个变量存储的值以及地址
varInStaticInited 的初始化以及更新
初始化是在 .data段, 初始化的值就是 3
然后更新是在 foo 中
读取 varInStaticInited 到 ax, 然后加1, 然后存放回去
因此在 foo 的多次调用期间, 它的值是类似于 持久化 的
varInStaticUnInited 的初始化以及更新
varInStaticUnInited 未初始化, 因此放在的是 .bss 段, 初始值为 0
register_tm_clones 中有对于 varInStaticUnInited 的读取, 目前不理解 是什么意思
然后更新是在 foo 中
读取 varInStaticUnInited到 ax, 然后加1, 然后存放回去
因此在 foo 的多次调用期间, 它的值是类似于 持久化 的
varInStackInited 的初始化以及更新
varInStackInited 对应的是 bp-18
初始化为 4, 然后从 bp-18 获取数据, 然后加1, 然后存放回去
因为每次 都是基于当前栈帧的 bp-18 进行操作的, 因此 每次都是 初始化为 4, 然后累增之后存储为5
varInStackUnInited 的初始化以及更新
varInStackInited 对应的是 bp-14
从上下文来看, beforeFoo 中局部变量多于 foo, beforeFoo 和 foo 之间无操作栈帧的相关指令, 因此 foo 的 bp 和 before 的 bp 会是相同的, 因此他们的局部变量区间 会有重叠的部分
beforeFoo 中的 bp-14 是 z, 其值为 10068
然后 我们这里 varInStackUnInited 是 bp-14, 继承了 beforeFoo 栈帧操作之后的影响, 得到的值也是 10068
然后 继续操作, 因此 第一次操作之后 varInStackUnInited 为 10069
然后 走剩余的流程, 并没有更新 bp-14, 最终 foo 结束, 弹出 foo 的栈帧
下一个 foo 继续进来, 两个 foo 的调用之前无 影响栈帧寄存器相关指令
因此 下一个 foo 的 bp-14 继承了上一个 foo 的 bp-14, 得到的值是 10069
第二次 累加之后, varInStackUnInited 的值为 10070
第三次同理 更新之后, varInStackUnInited 的值为 10071
varInMalloc 的初始化以及更新
初始化是在调用 malloc 的地方初始化
获取到 varInMalloc 的地址, 然后将 99 存放于 varInMalloc
完