考虑到内存分为四个部分:数据、堆、堆栈和代码,全局变量、静态变量、常量数据类型、局部变量(在函数中定义和声明)、变量(在主函数中)、指针和动态分配的空间(使用malloc和calloc)存储在内存中?

我认为他们的分配如下:

全局变量-------> data 静态变量------->数据 常量数据类型----->代码 局部变量(在函数中声明和定义)-------->堆栈 主函数-----> heap中声明和定义的变量 指针(例如char *arr, int *arr) ------->堆 动态分配空间(使用malloc和calloc) -------->堆栈

我仅从C的角度引用这些变量。

如果我错了,请指正,因为我是新来C的。


当前回答

指针(例如char*arr,int *arr) -->堆

不,它们可以在堆栈上,也可以在数据段中。他们可以指向任何地方。

其他回答

有些问题你答对了,但写问题的人至少在一个问题上骗了你:

global variables -------> data (correct) static variables -------> data (correct) constant data types -----> code and/or data. Consider string literals for a situation when a constant itself would be stored in the data segment, and references to it would be embedded in the code local variables(declared and defined in functions) --------> stack (correct) variables declared and defined in main function -----> heap also stack (the teacher was trying to trick you) pointers(ex: char *arr, int *arr) -------> heap data or stack, depending on the context. C lets you declare a global or a static pointer, in which case the pointer itself would end up in the data segment. dynamically allocated space(using malloc, calloc, realloc) --------> stack heap

值得一提的是,“栈”的正式名称是“自动存储类”。

流行的桌面架构将进程的虚拟内存划分为几个部分:

Text segment: contains the executable code. The instruction pointer takes values in this range. Data segment: contains global variables (i.e. objects with static linkage). Subdivided in read-only data (such as string constants) and uninitialized data ("BSS"). Stack segment: contains the dynamic memory for the program, i.e. the free store ("heap") and the local stack frames for all the threads. Traditionally the C stack and C heap used to grow into the stack segment from opposite ends, but I believe that practice has been abandoned because it is too unsafe.

C程序通常将具有静态存储持续时间的对象放入数据段中,在空闲存储区中动态分配对象,在其所在线程的调用堆栈中自动分配对象。

在其他平台上,如旧的x86真实模式或嵌入式设备上,情况显然完全不同。

我仅从C的角度引用这些变量。

From the perspective of the C language, all that matters is extent, scope, linkage, and access; exactly how items are mapped to different memory segments is up to the individual implementation, and that will vary. The language standard doesn't talk about memory segments at all. Most modern architectures act mostly the same way; block-scope variables and function arguments will be allocated from the stack, file-scope and static variables will be allocated from a data or code segment, dynamic memory will be allocated from a heap, some constant data will be stored in read-only segments, etc.

Variables/automatic variables ---> stack section Dynamically allocated variables ---> heap section Initialised global variables -> data section Uninitialised global variables -> data section (bss) Static variables -> data section String constants -> text section/code section Functions -> text section/code section Text code -> text section/code section Registers -> CPU registers Command line inputs -> environmental/command line section Environmental variables -> environmental/command line section

Linux最小可运行示例与反汇编分析

因为这是标准中没有指定的实现细节,所以让我们看看编译器在特定实现上做了什么。

在这个答案中,我将链接到做分析的具体答案,或者直接在这里提供分析,并在这里总结所有结果。

所有这些都在不同的Ubuntu / GCC版本中,不同版本之间的结果可能相当稳定,但如果我们发现任何变化,让我们指定更精确的版本。

函数中的局部变量

无论是main函数还是其他函数:

void f(void) {
    int my_local_var;
}

如:<value optimized out>在gdb中是什么意思?

o0:堆栈 -O3:如果不溢出,则寄存器,否则堆叠

关于为什么堆栈存在的动机,请参阅:在x86汇编中对寄存器使用的推/弹出指令的功能是什么?

全局变量和静态函数变量

/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;

/* DATA */
int my_global_implicit_explicit_1 = 1;

void f(void) {
    /* BSS */
    static int my_static_local_var_implicit;
    static int my_static_local_var_explicit_0 = 0;

    /* DATA */
    static int my_static_local_var_explicit_1 = 1;
}

如果初始化为0或未初始化(因此隐式初始化为0):.bss段,请参见:为什么需要.bss段? 否则:.data节

Char *和Char c[]

如:静态变量存储在C和c++的哪里?

void f(void) {
    /* RODATA / TEXT */
    char *a = "abc";

    /* Stack. */
    char b[] = "abc";
    char c[] = {'a', 'b', 'c', '\0'};
}

将非常大的字符串字面值也放在堆栈?或. data ?或者编译失败?

函数参数

void f(int i, int j);

必须经过相关的调用约定,例如:X86的https://en.wikipedia.org/wiki/X86_calling_conventions,它为每个变量指定了特定的寄存器或堆栈位置。

然后如所示<value optimized out>在gdb中是什么意思?, -O0然后将所有内容都放入堆栈,而-O3则尝试尽可能多地使用寄存器。

然而,如果函数内联,它们就像普通的局部变量一样被对待。

常量

我相信这没什么区别,因为你可以把它类型转换掉。

相反,如果编译器能够确定某些数据从未被写入,理论上它可以将其放置在.rodata中,即使不是const。

TODO微积分。

指针

它们是变量(包含地址,地址是数字),所以和其他所有变量一样:-)

malloc

这个问题对malloc没有太大意义,因为malloc是一个函数,并且在:

int *i = malloc(sizeof(int));

*i是一个包含地址的变量,所以它属于上述情况。

至于malloc在内部是如何工作的,当您调用它时,Linux内核将某些地址标记为其内部数据结构上的可写地址,当程序最初接触这些地址时,就会发生错误,内核启用页表,这样就可以在没有segaul的情况下进行访问:x86分页是如何工作的?

但是请注意,这基本上就是当你试图运行一个可执行文件时,exec系统调用在底层所做的事情:它标记它想要加载到的页面,并在那里编写程序,另参见:内核如何获得在linux下运行的可执行二进制文件?除了exec对加载到哪里有一些额外的限制(例如,代码是不可重定位的)。

在现代2020实现中,用于malloc的确切系统调用是mmap,在过去使用brk: malloc()使用brk()还是mmap()?

动态库

基本上得到映射到内存:https://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

环境变量和main的argv

上面的初始堆栈:https://unix.stackexchange.com/questions/75939/where-is-the-environment-string-actual-stored TODO为什么不在.data?