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

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


纠正错误的句子

constant data types ----->  code //wrong

本地常量变量----->堆栈

初始化全局常量变量----->数据段

未初始化的全局常量变量-----> BSS

variables declared and defined in main function  ----->  heap //wrong

在主函数-----> stack中声明和定义的变量

pointers(ex:char *arr,int *arr) ------->  heap //wrong

dynamically allocated space(using malloc,calloc) --------> stack //wrong

指针(例如:char *arr,int *arr) ------->该指针变量的大小将在堆栈中。

假设您正在动态分配n字节的内存(使用malloc或calloc),然后使指针变量指向它。现在n个字节的内存在堆中,指针变量需要4个字节(如果64位机器是8个字节),它将在堆栈中存储n个字节的内存块的起始指针。

注意:指针变量可以指向任何段的内存。

int x = 10;
void func()
{
int a = 0;
int *p = &a: //Now its pointing the memory of stack
int *p2 = &x; //Now its pointing the memory of data segment
chat *name = "ashok" //Now its pointing the constant string literal 
                     //which is actually present in text segment.
char *name2 = malloc(10); //Now its pointing memory in heap
...
}

动态分配空间(使用malloc,calloc) -------->堆


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

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


对于那些未来可能有兴趣了解这些内存段的访问者,我在C语言中写了关于5个内存段的要点:

一些提示:

每当C程序执行时,就会在RAM中分配一些内存用于程序执行。这个内存用于存储频繁执行的代码(二进制数据)、程序变量等。下面的内存段讲的是同样的: 通常有三种变量类型: 局部变量(在C语言中也称为自动变量) 全局变量 静态变量 你可以有全局静态变量或局部静态变量,但上面三个是父类型。

5 C中的内存段:

1. 代码段

The code segment, also referred as the text segment, is the area of memory which contains the frequently executed code. The code segment is often read-only to avoid risk of getting overridden by programming bugs like buffer-overflow, etc. The code segment does not contain program variables like local variable (also called as automatic variables in C), global variables, etc. Based on the C implementation, the code segment can also contain read-only string literals. For example, when you do printf("Hello, world") then string "Hello, world" gets created in the code/text segment. You can verify this using size command in Linux OS. Further reading

数据段

数据段被分为下面两部分,通常位于堆区域的下面,或者在某些实现中位于堆栈之上,但数据段从不位于堆和堆栈区域之间。

2. 未初始化的数据段

This segment is also known as bss. This is the portion of memory which contains: Uninitialized global variables (including pointer variables) Uninitialized constant global variables. Uninitialized local static variables. Any global or static local variable which is not initialized will be stored in the uninitialized data segment For example: global variable int globalVar; or static local variable static int localStatic; will be stored in the uninitialized data segment. If you declare a global variable and initialize it as 0 or NULL then still it would go to uninitialized data segment or bss. Further reading

3.初始化的数据段

This segment stores: Initialized global variables (including pointer variables) Initialized constant global variables. Initialized local static variables. For example: global variable int globalVar = 1; or static local variable static int localStatic = 1; will be stored in initialized data segment. This segment can be further classified into initialized read-only area and initialized read-write area. Initialized constant global variables will go in the initialized read-only area while variables whose values can be modified at runtime will go in the initialized read-write area. The size of this segment is determined by the size of the values in the program's source code, and does not change at run time. Further reading

4. 堆栈段

堆栈段用于存储在函数内部创建的变量(函数可以是主函数或用户定义的函数),如变量 函数的局部变量(包括指针变量) 传递给函数的参数 返回地址 一旦函数执行完成,存储在堆栈中的变量将被删除。 进一步的阅读

5. 堆段

这个段支持动态内存分配。如果程序员想动态分配一些内存,那么在C语言中可以使用malloc、calloc或realloc方法。 例如,当int* prt = malloc(sizeof(int) * 2)时,将在堆中分配8个字节,并返回该位置的内存地址并存储在ptr变量中。ptr变量将在堆栈或数据段上,这取决于它的声明/使用方式。 进一步的阅读


关于存储需要记住的一件事是假设规则。编译器不需要把一个变量放在特定的位置——相反,它可以把它放在任何它喜欢的地方,只要编译后的程序按照抽象C机器的规则运行,就像它在抽象C机器中运行一样。这适用于所有存储期限。例如:

a variable that is not accessed all can be eliminated completely - it has no storage... anywhere. Example - see how there is 42 in the generated assembly code but no sign of 404. a variable with automatic storage duration that does not have its address taken need not be stored in memory at all. An example would be a loop variable. a variable that is const or effectively const need not be in memory. Example - the compiler can prove that foo is effectively const and inlines its use into the code. bar has external linkage and the compiler cannot prove that it would not be changed outside the current module, hence it is not inlined. an object allocated with malloc need not reside in memory allocated from heap! Example - notice how the code does not have a call to malloc and neither is the value 42 ever stored in memory, it is kept in a register! thus an object that has been allocated by malloc and the reference is lost without deallocating the object with free need not leak memory... the object allocated by malloc need not be within the heap below the program break (sbrk(0)) on Unixen...


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?