前话
之前一直没能理解C++编译的逻辑,所以我一直很好奇,主程序的cpp文件里只注明了h头文件,而头文件跟cpp文件也并不要求一一对应,那么编译的时候,系统到底是如何从h文件往回找到相对应的函数源文件呢?
现在搞明白了,这里会用g++来做一个简单的逻辑梳理。
1、简介
g++是linux下最常用的编译工具,而在windows系统中,我们常直接使用vs等软件自带编译器进行编译,其实是一样的。
2、编译逻辑
#include
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
std::cin.get();
//test
}
通常情况下,我们编译这个程序是用这个指令
g++ test.cpp -o test
而从完整的逻辑上来讲,cpp文件的编译要经过四个阶段,分别是预处理(Preprocessing)、编译(Compilation)、汇编 (Assembly)和链接(Linking)。
2.1 预处理(Preprocessing)
g++ -E test.cpp -o test.i
或者
g++ -E test.cpp
第一句指令会输出test.i文件,而第二句指令会直接将结果从窗口输出。通过输出结果我们就可以知道,预处理的其中一个作用,其实就是把头文件全部复制到test文件中来。
更准确的说,这一步会处理的是Preprocessing语句,包括include、defind、 if 等等,换而言之,我们为了方便而将程序拆成了各个不同的模块或者表达方式,而Preprocessing是反过来,将我们写成的这些程序重新生成一个完整的整体。
很多时候,程序中所包含的头文件中,又会包含新的头文件,特别是像iostream这种。所以,为了控制文件的大小,我们要尽量避免多余的头文件。
2.2 编译(Compilation)
g++ -S test.i -o test.s
这里是对生成的test.i文件编译,生成汇编代码。
所以虽然我们所写为c++,但实际上到机器运行时,还是先需要转化成汇编代码,才能进行下一步编译。
2.3 汇编 (Assembly)
g++ -c test.s -o test.o
将上一步生成的汇编代码进行编译,编译成机器代码。
2.4 链接(Linking)
g++ test.o -o test
负责将程序的目标文件与所需的所有附加的目标文件连接起来,这个时候只需要执行test文件,就可以实现代码 Hello,World。
2.5 error
在我们编写程序后进行一步到位的编译时,经常会出错,那么理解了编译的四个环节之后,我们就可以简单的去理解一些问题的原因。例如:
如果报错error CXXXX:那么就是编译(Compilation)出现了错误,一般是函数等未做声明
如果报错error LinkXXXX: 那么就是链接(Linking)出现了错误,一般是未找到函数的定义。
2.6 编译优化
编译优化并非一定会进行的,不过这里也顺便讲一下(例子)
程序优化的内容包括:与程序 毫不相关的函数、多余的参数变量,消除多余步骤等。不同等级的优化程度不一样,一般O2就够了,O3以上有时候会出现编译时间长,编译失败等现象。
3、多文件编译
当我们需要同时进行多个cpp文件编译时。例如:
log.h
void Log(const char* msg);
log.cpp
#include <iostream>
void Log(const char* msg)
{
std::cout << "Hello World!" << std::endl;
//test
}
test.cpp
#include <iostream>
#include 'log.h'
int main()
{
Log("Hello World");
std::cin.get();
}
那么这个时候,如果按照我们一开始的逻辑,使用函数时会遍历文件夹的所有cpp文件去找相对应的函数,那么我们的程序也应该是g++ test.cpp -o test。但根据我们梳理的四个步骤,可以发现实际上并不应该这么写,这么写的话,只有log.h跟test.cpp被纳入编译的初始文件。正确的编译指令应该这么写
g++ Log.cpp test.cpp -o test
而这样的话,我们就会迎来一个新的问题,如果一个项目文件很多,我们根本不可能像这样一个文件一个文件的去输入来编译,这样效率太慢了,所以就有了CMakeList的出现。
在各种项目文件夹中,我们都可以看见他,可以简单的理解成一个批量编译的脚本
4、最后
理解了编译的过程,那么还将有伴随而来的新的问题,都将在后面一一处理。
1、CMakeList的书写
2、如果多个cpp文件都用到同一个h文件,那么编译的时候不就会被重复编译?
3、函数的声明和定义?