C++程序执行过程

C++程序执行过程:预处理、编译、汇编,链接,执行

目录

  • C++程序执行过程:预处理、编译、汇编,链接,执行
    • 预处理
      • 1. 包含头文件
      • 2. 条件编译
      • 3. 处理宏
      • 4. 将注释替换成空格
    • 编译
    • 汇编
    • 链接
    • 运行

预处理

预处理操作针对#开头的语句,没有分号

g++ -E test.cpp > test.i // 生成预处理文件

预处理语句类型及作用:

1. 包含头文件

include \包含已经安装的C++库;#include "myown.h"包含自己编写的库。程序在寻找被include的库时,如果是<>则优先在系统目录中寻找,找不到再来程序文件夹下寻找;""则相反。

2. 条件编译

#ifdef...#endif#ifndef...#endif。作用:最常用在避免重复包含头文件中,比如在一个较大的工程中,自己编写了一个头文件myown.h,在这个工程中多个cpp文件都需要include这个头文件,那么在链接过程中会因为重复包含头文件而报错。于是可以在myown.h的开头写入如下语句:

#ifndef _MYOWN_H
#define _MYOWN_H
//头文件程序内容
#endif

这样,在第一次包含这个头文件的时候,_MYOWN_H被定义,此后再遇到#include "myown.h"的命令,进入mywon.h时会发现已经包含了,避免了重复包含。

3. 处理宏

宏中定义了函数的进行展开,定义了变量或者名称替换的进行替换。因为预编译阶段不分析语义,而只是进行简单的字符替换,所以宏定义函数时要注意将所有变量都加上括号,否则就会出现下面所示的错误:

#include <iostream>
#define right
#define mian main  //替换
#define rSQ(x) ((x) * (x))  //正确写法
#define fSQ(x) x * x  //错误写法
using namespace std;

int mian(){
	int a = 5;
#ifdef right
	cout << rSQ(a + 2) << endl;
#endif
#ifndef right
	cout << fSQ(a + 2) << endl;
#endif
	return 0;
}

正确生成的预处理文件的结尾是这样的:

int main(){ 
 int a = 5;

 cout << ((a + 2) * (a + 2)) << endl;




 return 0;
}

错误生成的预处理文件的结尾是这样的:

using namespace std;

int main(){
 int a = 5;




 cout << a + 2 * a + 2 << endl;

 return 0;
}

所以为了避免出错,所有能加括号的地方都要加上括号。

4. 将注释替换成空格

如上述程序所示,预处理之后不需要的#ifndef等语句都变成了空行。

编译

编译过程将预处理之后的test.i文件翻译成汇编语言,源程序是高级语言,汇编语言程序是低级语言,不同的高级语言翻译的汇编语言相同。

g++ -S test.cpp // 生成汇编语言文件test.s

编译过程中有词法分析、语法分析、语义分析等步骤,会生成符号表,这个符号表似乎比较重要,以后有机会再来更~

汇编

汇编过程是将上一步生成的test.s文件翻译成二进制机器码,即生成目标文件(object file)test.o

g++ -c test.cpp // 生成机器码(目标文件)

链接

链接这个阶段会将目标文件test.o和之前include的库文件链接在一起,生成可执行文件,命令就是Linux里熟悉的这一行啦~

g++ test.cpp -o test // 生成可执行文件

这里静态库和动态库的链接有区别:

  • 静态库.a文件本身也是类似上一步生成的test.o这种目标文件(一般是.o文件的集合),所以静态库的链接就是把库文件和自己的.o文件拼接在一起,生成的可执行文件与静态库本身再无任何关系,故方便程序在不同平台上的移植,也就是说生成了这个可执行文件之后,拷贝到另外一个没有上述静态库的系统上之后,依然能够正常运行。但是缺点也是显而易见的,体积大,全量更新(即如果库文件被更新,那么生成的可执行文件也要重新生成),重复链接占用内存(每次调用都会在内存中生成一个副本)。
  • 动态库.so文件则不同,其链接过程说成在运行阶段更合适。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该动态库的实例即可,所以动态库也称共享库。动态库优点是不占内存、增量更新,缺点是不方便移植
  • 二者的区别在于库文件被载入的时刻不同,这也决定了他们各自的特点。

运行

./test

运行可执行文件即可完成程序功能。

你可能感兴趣的:(c++)