用g++命令执行C++多文件项目
《那些被编译器隐藏了的过程》一节中讲到,C 或者 C++ 程序的执行过程分为 4 步,依次是
- 预处理
- 编译
- 汇编
- 链接
我们知道,C++ 多文件编程中有头文件(.h 为后缀)和源文件(.cpp为后缀)之分。需要注意的是,在执行 C++项目时,头文件是不需要经历以上这 4 个阶段的,只有项目中的所有源文件才必须经历这 4 个阶段。
假设有这样一个 C++ 项目:
//student.h class Student { public: const char *name; int age; float score; void say(); }; //student.cpp #include <iostream> //std::cout、std::endl #include "student.h" //Student void Student::say() { std::cout << name << "的年龄是" << age << ",成绩是" << score << std::endl; } //main.cpp #include "student.h" //Student int main() { Student *pStu = new Student; pStu->name = "小明"; pStu->age = 15; pStu->score = 92.5f; pStu->say(); delete pStu; //删除对象 return 0; }
该项目正确的执行结果为:
1) 经历预处理阶段,执行如下命令:
[root@bogon ~]# g++ -E main.cpp -o main.i [root@bogon ~]# g++ -E student.cpp -o student.i
其中,
- -E 选项用于限定 g++ 编译器只进行预处理而不进行后续的 3 个阶段;
- -o 选项用于指定生成文件的名称。
- Linux 系统中,通常用 ".i" 作为 C++ 程序预处理后所得文件的后缀名。
感兴趣的读者可自行运行cat main.i指令查看 main.i 文件中的内容(student.i文件也可以用此方式查看)。
2) 经历编译阶段,即对预处理阶段得到的 -i 文件做进一步的语法分析,生成相应的汇编代码文件。继续执行如下命令:(个人:编译指令选项为大写S,生成的文件后缀为小写s)
[root@bogon ~]# g++ -S main.i -o main.s [root@bogon ~]# g++ -S student.i -o student.s
其中,
- -S 选项用于限定 g++ 编译器对指定文件进行编译,
- 得到的汇编代码文件通常以“.s”作为后缀名。
感兴趣的读者可以使用 cat 命令查看生成文件的内容。
3) 经历汇编阶段,即将汇编代码文件转换成可以执行的机器指令。继续执行如下命令:
[root@bogon ~]# g++ -c main.s -o main.o [root@bogon ~]# g++ -c student.s -o student.o
- -c 指令用于限定 g++ 编译器只进行汇编操作,
- 最终生成的目标文件(本质就是二进制文件,但还无法执行)通常以“.o”作为后缀名。
4) 经历链接阶段,即将所有的目标文件组织成一个可以执行的二进制文件。执行如下命令:(个人:链接阶段的g++命令没有任何指令选项)
[root@bogon ~]# g++ main.o student.o -o student.exe
注意,
- 如果不用 -o 指定可执行文件的名称,默认情况下会生成 a.out 可执行文件。
- Linux 系统并不以文件的扩展名来区分文件类型,所以 a.out 和 student.exe 都是可执行文件,只是文件名称有区别罢了。
经历以上 4 步,最终会生成 student.exe 可执行文件,其执行结果为:
[root@bogon ~]# ./student.exe 小明的年龄是15,成绩是92.5
注意:“./”表示当前目录,不能省略。
读者可能觉得整个执行过程非常繁琐,直接执行如下命令即可生成最终的可执行文件:
[root@bogon ~]# g++ main.cpp student.cpp -o student.exe [root@bogon ~]# ./student.exe 小明的年龄是15,成绩是92.5