(2)编译过程:一个.cpp文件到一个exe会经过哪些步骤
比如我们main函数所在的.obj文件上述了是需要使用taolaoda.obj文件中的函数,且在mian函数所在的.obj中声明了,链接器会去找其他.obj文件中找找到那个函数,然后将多个.obj文件中的东西复制到一个exe可执行文件中,我们需要使用其他文件中的函数和变量,这个就是链接器去找的,找到了虽有需要找到然后缝缝补补成一exe。看我们引用其他文件中的一个外部变量 a,但是我在其他文件中没有
一、
原文链接:https://blog.csdn.net/m0_47557768/article/details/116380280
我们知道当我们用C++编译器编辑一个文件时,这个文件就是一个扩展名为.c或.cpp文件,而当我们进行编译运行之后,编译器会为我们自动生成一个扩展名为.exe文件。那么这个过程是怎样的呢?接下来我们来解析这样一个过程。
首先我们来看图解。
过程解析如下:
(一)预处理阶段。(.c/.cpp 文件=》.i文件)
首先我们会对我们编辑得到的源代码(即扩展名为.c/.cpp文件)通过预处理器进行预处理,这一部分是由我们的编译器帮我们完成的。预处理器做的事情就是将原始源文件中的所有预处理器指令替换为暗示指令的实际库代码。那么什么是预处理指令呢?实际上这些是我们在代码很常见的,如#include和#define指令。之后,生成的文件基本上被取代并获得扩展名为.i文件。
(二)编译器编译阶段。(.i文件 =》.s文件)
接下来是编译器的处理阶段,这个阶段是把高级语言翻译成低级语言的过程,也负责检查源代码的语法/语法。若发现无误,则会将文件转换为扩展名为.s的文件,即我们所知的汇编代码。
(三)目标文件转换阶段。(.s文件 =》.o/.obj目标文件)
得到汇编文件之后,要对其进行转换,即该过程是将汇编级语言转换为机器级语言(一般为二进制格式),此时生成的文件就是我们的目标文件,扩展名为.o或.obj。
(四)链接阶段。(.o/.obj目标文件 =》.exe可执行文件)
C++语言支持分离式编译(这里指的编译是指上面(一)至(三)阶段)机制的,该机制允许将程序分割为若干个文件,每个文件可独立编译。那么多个已编译的文件如何合并呢?答案就是在此阶段。该阶段通过链接器将一个或多个目标文件合并到一个可执行文件,即将扩展名为.obj / .o文件转换为扩展名为.exe文件。
以上的四个阶段就是.cpp文件转换为.exe文件的过程。
注:我们平常所说的“编译”是一个整体,即包括预处理,编译和汇编三个阶段。它在这些步骤中基本上将高级语言转换为机器级语言,并生成单个二进制对象文件。若编译(但不链接)三个单独的文件,则将创建三个作为输出的目标文件。
二、原文链接:https://blog.csdn.net/taolaodawho/article/details/109472892
从一个.cpp文件到一个exe会经过如下几步
1.预处理
2.编译
3.汇编
4.链接
1:预处理阶段有预处理器进行,会将每一个.cpp(源文件(c语言程序和c++语言程序是一样的)预处理器会将所有源文件中的与预处 理指令进行处理,所谓的预处理执行就是 #开头的语句
如#define #include #if 1 #endif 宏定义,头文件包含 条件偏移等等都是预处理指令
#pragma once(加上头文件的开头,能够保证这个头文件的内容只被编译一次)上述等等都是最常见的预处理指令
vs可以配置预处理器生成预处理阶段生成的预处理文件.i文件
设置好后点重新生成,可以看到给两个源文件都生成了.i文化
这是我Main.cpp文件中的内容
#include"taolaoda.h"
#include<stdio.h>
#define LOG(x) printf("%d\n",x)
int main() {
LOG(add(1, 2));
LOG(sub(10, 20));
LOG(mul(3, 5));
LOG(div(3, 6));
getchar();
}
这是我taolaoda.cpp文件中内容
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) {
if (0 == b) {
return -1;
}
return a / b;
}
这是我们taolaoda.h我们的内容
#pragma once
int add(int a,int b);
int sub(int a,int b);
int mul(int a, int b);
int div(int a, int b);
打开Main.i,可以看到一开始就是把taolaoda.h文件中的内容复制到Main.i中了
这个文件有1万多行,因为#include<stdio.h>,可以看到后面本来源文件使用的是宏,全都替换成了定义的
所以#defien宏定义的效率为什么高,因为它在预处理阶段就替换了不会影响执行使其的效率
而且实现一个简单的功能如何封装成宏函数,而不是普通函数,也能实现模块化,而且不用给函数开辟堆栈,效率会更高
taolaoda.i文件几乎没有什么变化,因为根本没有taolaoda.cpp里面没有使用预处理指令
我将taolaoda.cpp中加一个条件偏移,和一个#Include包含taolaoda.h看看 在重新生成
2:汇编将是将预处理生成的.i文件作为输入,生成.asm汇编文件作为输出
可能有的人有些奇怪汇编文件不是.s为什么是.asm linux下是.s Windows下是.asm
3:汇编就是将生产的.asm(汇编)作为输入 .obj文件作为输出,我们知道CPU只能是被二进制,汇编程序作为机器指令的助记符,只是给人看的,CPU识别不了,CPU只能是被二进制,汇编就是将汇编文件转换成二进制文件.obj 也称为目标文件
4:链接将多个.obj文件作为输入生成一个exe文化可执行文件作为输出
比如我们main函数所在的.obj文件上述了是需要使用taolaoda.obj文件中的函数,且在mian函数所在的.obj中声明了,链接器会去找其他.obj文件中找找到那个函数,然后将多个.obj文件中的东西复制到一个exe可执行文件中,我们需要使用其他文件中的函数和变量,这个就是链接器去找的,找到了虽有需要找到然后缝缝补补成一exe
链接器会将每个目标文件看成一组外部对象(全局的),每个外部对象看成内存中的一部分,链接器还会处理一些命名冲突
如果一个文件中不允许有两个外部对象名字一样,
预处理阶段由预处理器做将源文件作为输入,.i文件作为输出
编译阶段由编译器将,i文件作为输入,.asm文件作为输出
汇编阶段由汇编器将.asm文件作为输入,.obj文件作为输出
以上每个阶段文件生成数,与输出数相同,
链接器是将生成的多个obj文件补合成一个可执行文件
发送在编译期间的错误最容易找,发送链接阶段的错误很让通头痛(如果没有理解链接阶段做了什么)发送了链接错误
那就是噩梦
看我们引用其他文件中的一个外部变量 a,但是我在其他文件中没有定义,然后链接的时候就找到了,然后就给了一个链接错误
当然这是最简单的链接错误
原文链接:https://blog.csdn.net/taolaodawho/article/details/109472892
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)