内存中程序的结构
以下是任何程序在内存中加载时的基本结构。
+--------------------------+
| |
| command line |
| arguments |
| (argc and argv[]) |
| |
+--------------------------+
| Stack |
| (grows-downwards) |
| |
| |
| |
| F R E E |
| S P A C E |
| |
| |
| |
| |
| (grows upwards) Heap |
+--------------------------+
| |
| Initialized data |
| segment |
| |
+--------------------------+
| |
| Initialized to |
| Zero (BSS) |
| |
+--------------------------+
| |
| Program Code |
| |
+--------------------------+
需要注意的几点:
- 数据段
- 初始化的数据段(由程序员初始化为显式初始值设定项)
- 未初始化的数据段(初始化为零数据段 - BSS [块以符号开头])
- 代码段
- 堆栈和堆区域
数据段
数据段包含由包含初始化值的用户显式初始化的全局和静态数据。
数据段的另一部分称为BSS(因为旧的IBM系统已将该段初始化为零)。它是操作系统将内存块初始化为零的内存部分。这就是未初始化的全局数据和静态数据将默认值为零的方式。此区域是固定的,具有静态大小。
数据区域根据显式初始化分为两个区域,因为要初始化的变量可以逐个初始化。但是,未初始化的变量不需要逐个使用 0 显式初始化。取而代之的是,初始化变量的工作留给操作系统。此批量初始化可以大大减少加载可执行文件所需的时间。
大多数情况下,数据段的布局由底层操作系统控制,仍然一些加载器将部分控制权交给用户。此信息在嵌入式系统等应用中可能很有用。
可以使用代码中的指针对该区域进行寻址和访问。Auto 变量在每次需要变量时都会有初始化变量的开销,并且需要代码来执行该初始化。但是,数据区域中的变量没有这样的运行时重载,因为初始化只执行一次,并且在加载时也执行。
代码段
程序代码是可执行代码可供执行的代码区域。这个区域也是固定大小的。这只能通过函数指针访问,而不能由其他数据指针访问。这里要注意的另一个重要信息是,系统可能会将此区域视为只读内存区域,并且在此区域中写入的任何尝试都会导致未定义的行为。
常量字符串可以放在代码或数据区域中,这取决于实现。
尝试写入代码区域会导致未定义的行为。例如(我将仅提供基于示例的示例),以下代码可能会导致运行时错误甚至使系统崩溃。C
int main()
{
static int i;
strcpy((char *)main,"something");
printf("%s",main);
if(i++==0)
main();
}
堆栈和堆区域
对于执行,程序使用两个主要部分,堆栈和堆。堆栈帧是在函数的堆栈和用于动态内存分配的堆中创建的。堆栈和堆是未初始化的区域。因此,内存中碰巧存在的任何内容都将成为在该空间中创建的对象的初始(垃圾)值。
让我们看一个示例程序,以显示哪些变量存储在何处,
int initToZero1;
static float initToZero2;
FILE * initToZero3;
// all are stored in initialized to zero segment(BSS)
double intitialized1 = 20.0;
// stored in initialized data segment
int main()
{
size_t (*fp)(const char *) = strlen;
// fp is an auto variable that is allocated in stack
// but it points to code area where code of strlen() is stored
char *dynamic = (char *)malloc(100);
// dynamic memory allocation, done in heap
int stringLength;
// this is an auto variable that is allocated in stack
static int initToZero4;
// stored in BSS
static int initialized2 = 10;
// stored in initialized data segment
strcpy(dynamic,”something”);
// function call, uses stack
stringLength = fp(dynamic);
// again a function call
}
或者考虑一个更复杂的例子,
// command line arguments may be stored in a separate area
int main(int numOfArgs, char *arguments[])
{
static int i;
// stored in BSS
int (*fp)(int,char **) = main;
// points to code segment
static char *str[] = {"thisFileName","arg1", "arg2",0};
// stored in initialized data segment
while(*arguments)
printf("\n %s",*arguments++);
if(!i++)
fp(3,str);
}
希望这有帮助!