一、理解C语言程序编译过程
对于一个编写完成的C语言程序,编译器是如何将.c 、.cpp等合法文件通过编译生成一个可执行程序?
编译器需要完成的至少包括四个过程:
1)由与处理程序执行C源文件中的预处理指令:这个过程主要处理的宏定义的替换
2)C编译器把经过预处理的C代码文件编译成汇编代码文件:汇编代码在这里作为一种中间文件
3)汇编编译器把汇编代码编译成目标代码文件:生成.o后缀的可重定向目标文件,目标代码其实已经是以机器代码形式存在,只不过有一些符号的地址需要链接时才能解决;
4)链接程序把所有目标代码链接起来产生可执行文件。
通常前三个步骤称为编译,把所有需要确定的地址符号记录下来,最后一个步骤称为链接,找到记录下来的地址符号找到它们定义点并计算给予合适的地址,确定后链接程序便可生成可执行文件。
例子:比如调用printf函数,printf属于C语言标准库中的函数,是已经被编译成库文件,我们通过链接这些库文件便可以产生可执行文件。
二、理解C++内存区域
C++主要有五种内存区域:
1)常量数据:该区域存储只读数据,在编译期就已经知道值得数据,包括字符串,一般不能对该区域的内容进行修改,在整个程序生存期中一直存在。实例化得对象是不能存储在这个区域中的。
2)栈:存储的是自动变量,在被定义的时候自动构造,域结束的时候立即销毁。栈内存分配比动态内存分配快很多,因为只涉及到指针的自增操作。
3)自由存储:通过new / delete进行分配和释放。对象的生存期可能小于所分配的存储空间的生存期,意思就是该区域给对象分配了空间后,不要求立即初始化对象,销毁对象时,不要求立即释放空间。可以通过指针对已分配空间但还没有进入生存期的对象进行访问,但是不能访问对象中任何一个非静态成员,不能获得它们地址,更不能进行其他操作。
4)堆:和自由存储一样,属于动态内存区域。通过malloc/free以及这些函数的其他形式进行分配或释放。注意某些编译器默认全局运算符new/delete会用malloc/free进行实现,但两者还是不同,堆分配的内存不能再自由存储被安全释放,反过来一样。
5)全局/静态:程序启动时,全局变量(对象)、静态变量(对象)就已经分配了空间,只有在执行的时候才被初始化。注意跨越多个编译单元的全局变量,它们初始化顺序未定义,同时要注意它们之间的依赖关系,通常可以使用指针对未初始化的对象存储空间进行访问操作,但是不能在对象的生存期之外来使用或者引用非静态的成员变量或成员函数。
三、调用函数与栈
简单来讲,调用函数需要经历以下几个过程:1)参数入栈;2)指令执行点转移到函数代码入口;
首先想到栈的特点是后进先出(LIFO)。一个程序可以分为两个部分构成:数据和代码,而数据分为两类,一类是“静态的”,也就是说在程序运行中的整个过程, 数据在内存中的位置是固定不变的,包括外部变量、内部静态变量;另一类是“动态的”,即运行中的内存位置不是固定的,包括内部(非静态)变量,通常这种内部变量的存取便是使用栈进行操作。
注意一点:栈的存储顺序是由高地址 -> 低地址;函数参数入栈的顺序从右到左。
*下一期更新外部变量的链接性质、静态内部变量、函数定义和声明