编译时内存分配主要是指在程序编译阶段,由编译器为程序中的各种静态数据分配内存空间。这些静态数据包括全局变量、静态变量、常量等。这些内存分配在编译时就已经确定,在程序加载到内存后,这些内存空间会被操作系统分配并初始化。编译时内存分配的几个主要方面:
1. 静态存储区
编译时为静态变量和全局变量分配的内存区域。所有的静态变量和全局变量在编译时就确定了内存地址,并在程序运行期间保持不变。
全局变量:在文件的任何地方定义的变量,在程序的整个生命周期内都存在。
静态变量:使用static关键字定义的变量,作用域仅限于定义它的文件、函数或代码块,但生命周期同样覆盖整个程序执行周期。
2. 常量区
编译器在编译时为程序中的常量分配内存。例如,字符串常量在编译时就已经确定了它们的内存地址。
3. 已初始化和未初始化的数据段
已初始化的数据段(.data段):存储程序中已初始化的全局变量和静态变量。这些变量在编译时分配内存,并在程序加载时初始化为编译器指定的值。
未初始化的数据段(BSS段,.bss段):存储程序中未初始化的全局变量和静态变量。在程序加载时,这些变量会被操作系统自动初始化为零。
4. 代码段
代码段存储程序的可执行代码。在编译时,编译器生成目标代码并将其放入代码段中。在程序运行时,这些代码会被加载到内存中并执行。
编译时内存分配的步骤
语法分析:编译器首先分析程序的源代码,生成抽象语法树(AST)。
语义分析:检查变量的定义和使用是否合法,并记录变量的属性(如类型、作用域、初始值等)。
符号表生成:编译器维护一个符号表,记录所有变量和常量的信息,包括它们的内存地址、类型和作用域等。
内存地址分配:根据符号表的信息,编译器为每个变量和常量分配内存地址。
目标代码生成:编译器生成目标代码,并将所有静态数据和代码段的信息写入目标文件中。