C中虚拟内存的组织
Organization of Virtual Memory in C
对于以下各项,它似乎存储在内存中的什么位置,以什么顺序存储:全局变量、局部变量, 静态局部变量, 函数参数, 全局常量, 局部常量,函数本身(main是一个特例吗?),动态分配的变量.
我将如何通过实验评估这一点,即使用 C 代码?
我知道
全局变量 -- 数据
静态变量——数据
常量数据类型 -- 代码
局部变量(在函数中声明和定义)-- stack
在 main 函数中声明和定义的变量 -- stack
指针(例如:char *arr,int *arr
)——数据或堆栈
动态分配 space(使用 malloc、calloc)——堆
您可以编写一些代码来创建以上所有内容,然后打印出它们的地址。例如:
void func(int a) {
int i = 0;
printf("local i address is %x\n", &i);
printf("parameter a address is %x\n", &a);
}
printf("func address is %x\n", (void *) &func);
请注意函数地址有点棘手,您必须将其转换为 void* 并且在获取函数地址时省略 ()。比较内存地址,您将开始了解图片或事物所在的位置。通常文本(指令)在底部(最接近 0x0000),堆在中间,堆栈从顶部开始向下增长。
理论上
就内存位置而言,指针与其他变量没有区别。
局部变量和参数可能分配在堆栈上或直接分配在寄存器中。
常量字符串将存储在一个特殊的数据部分,但基本上与数据相同的位置。
数值常量本身不会存储在任何地方,它们会被放入其他变量或直接翻译成CPU指令。
例如 int a = 5;
会将常量 5 存储到变量 a
中(实际内存与变量相关,而不是常量),但是 a *= 5
将生成乘以 a
由常数 5.
就内存位置而言,main
只是一个与其他函数一样的函数。局部 main
变量与任何其他局部变量没有区别,main
代码像任何其他函数一样位于代码部分的某处,argc
和 argv
只是参数其他(它们由调用 main
的启动代码提供),等等
代码生成
现在,如果您想查看编译器和 运行time 将所有这些东西放在哪里,一种可能是编写一个小程序,每个程序都定义了一些,然后要求编译器生成一个汇编列表.然后您将看到每个元素是如何存储的。
对于堆数据,您将看到对 malloc 的调用,它负责与动态内存分配器连接。
对于堆栈数据,您会看到对堆栈指针(x86 架构上的 ebp 寄存器)的奇怪引用,它们将同时用于参数和(自动)局部变量。
对于 global/static 数据,您将看到以您的变量命名的标签。
常量字符串可能会标有一个糟糕的名称,但您会注意到它们都进入一个部分(通常名为 bss),该部分将链接到数据旁边。
运行时间地址
或者,您可以 运行 这个程序并要求它打印每个元素的地址。但是,这不会向您显示寄存器用法。
如果您使用可变地址,您将强制编译器将其放入内存,否则它可以将其保存在寄存器中。
另请注意,内存组织取决于编译器和系统。使用 gcc 和 MSVC 编译的相同代码可能具有完全不同的地址和完全不同顺序的元素。
代码优化器也可能会做一些奇怪的事情,所以我建议先在禁用所有优化的情况下编译您的示例代码。
不过,看看编译器如何提高大小 and/or 速度可能会很有趣。
对于以下各项,它似乎存储在内存中的什么位置,以什么顺序存储:全局变量、局部变量, 静态局部变量, 函数参数, 全局常量, 局部常量,函数本身(main是一个特例吗?),动态分配的变量.
我将如何通过实验评估这一点,即使用 C 代码?
我知道
全局变量 -- 数据
静态变量——数据
常量数据类型 -- 代码
局部变量(在函数中声明和定义)-- stack
在 main 函数中声明和定义的变量 -- stack
指针(例如:char *arr,int *arr
)——数据或堆栈
动态分配 space(使用 malloc、calloc)——堆
您可以编写一些代码来创建以上所有内容,然后打印出它们的地址。例如:
void func(int a) {
int i = 0;
printf("local i address is %x\n", &i);
printf("parameter a address is %x\n", &a);
}
printf("func address is %x\n", (void *) &func);
请注意函数地址有点棘手,您必须将其转换为 void* 并且在获取函数地址时省略 ()。比较内存地址,您将开始了解图片或事物所在的位置。通常文本(指令)在底部(最接近 0x0000),堆在中间,堆栈从顶部开始向下增长。
理论上
就内存位置而言,指针与其他变量没有区别。
局部变量和参数可能分配在堆栈上或直接分配在寄存器中。
常量字符串将存储在一个特殊的数据部分,但基本上与数据相同的位置。
数值常量本身不会存储在任何地方,它们会被放入其他变量或直接翻译成CPU指令。
例如 int a = 5;
会将常量 5 存储到变量 a
中(实际内存与变量相关,而不是常量),但是 a *= 5
将生成乘以 a
由常数 5.
main
只是一个与其他函数一样的函数。局部 main
变量与任何其他局部变量没有区别,main
代码像任何其他函数一样位于代码部分的某处,argc
和 argv
只是参数其他(它们由调用 main
的启动代码提供),等等
代码生成
现在,如果您想查看编译器和 运行time 将所有这些东西放在哪里,一种可能是编写一个小程序,每个程序都定义了一些,然后要求编译器生成一个汇编列表.然后您将看到每个元素是如何存储的。
对于堆数据,您将看到对 malloc 的调用,它负责与动态内存分配器连接。
对于堆栈数据,您会看到对堆栈指针(x86 架构上的 ebp 寄存器)的奇怪引用,它们将同时用于参数和(自动)局部变量。
对于 global/static 数据,您将看到以您的变量命名的标签。
常量字符串可能会标有一个糟糕的名称,但您会注意到它们都进入一个部分(通常名为 bss),该部分将链接到数据旁边。
运行时间地址
或者,您可以 运行 这个程序并要求它打印每个元素的地址。但是,这不会向您显示寄存器用法。
如果您使用可变地址,您将强制编译器将其放入内存,否则它可以将其保存在寄存器中。
另请注意,内存组织取决于编译器和系统。使用 gcc 和 MSVC 编译的相同代码可能具有完全不同的地址和完全不同顺序的元素。
代码优化器也可能会做一些奇怪的事情,所以我建议先在禁用所有优化的情况下编译您的示例代码。
不过,看看编译器如何提高大小 and/or 速度可能会很有趣。