C++究竟是如何工作的(有关编译和链接的一点看法,vs2022)上—— 编译部分

这里是想要从事游戏行业的普普通通大学生,最近在复习c++,边学边写博客巩固自己学到的知识,共勉。

C++是如何工作的

c++是一种高级语言,我们写的c++代码并不能直接让计算机的cpu明白我们要干什么,必须通过编译器和链接器进行编译和链接后才能得到可以运行的二进制文件。

(1)编译 :把文本形式的源代码翻译成机器语言,并形成目标文件。
(2)连接 :把目标文件 操作系统的启动代码和库文件组织起来形成可执行程序。

值得注意的是c++并不关心文件,所有的文件如(.cpp .h)仅仅只是为了给
c++提供源码,如果是.cpp那么就按照普通的c++文件进行编译,如果是.h就按照头文件的方式进行编译,如果你喜欢你可以自己造一个.zhangsan文件,只要你告诉编译器像处理.cpp一样处理.zhangsan就好了。

每一个.cpp都会在编译阶段被编译成独立的.obj文件,但.h并不会被编译成.obj,因为.h会在预处理的时候通过“#include”命令包含进.cpp中。当每一个.cpp都被编译成独立的.obj时,链接器就会开始将这些.obj链接起来,组合成一个可运行的.exe。

C++编译器是如何工作的(vs2022)

创建一个c++空项目,注意最上面的解决方案配置和解决方案平台。
在这里插入图片描述
编写一段简单的代码并使用ctrl + f7进行编译(单独编译,不链接)。
在这里插入图片描述
可以看到主函数并没有返回值,因为主函数很特殊,也只有它一个函数有这么特殊,那就是编译器会给它一个默认的返回值0。
编译成功后打开工程所在文件夹可以找到编译后生成的.obj文件。
在这里插入图片描述

1、预编译

编译大概可以分为两个阶段,第一个阶段是预处理阶段,这个阶段会进行一些文本替换,会生成不含#指令的.i文件,预处理命令以#开头。该阶段会拷贝#include里的内容到cpp中,进行宏定义#define的替换,和条件编译指令如#if,#ifdef,#endif等。

1、1 #include的替换

上面有提到“.h并不会被编译成.obj,因为.h会在预处理的时候通过“#include”命令包含进.cpp中”,当编译器注意到#include时,它会进入xxxx.h,阅读其中的代码并将其全部拷贝到.cpp文件中。

我们在工程中再创建一个test.cpp文件,并使用ctrl + f7进行单独编译。
在这里插入图片描述
我们回到工程文件目录会发现多了一个test.obj文件,且其文件大小远远小于main.obj。
在这里插入图片描述
这两个文件最大的不同便是main.cpp中有#include这个预处理命令,编译器在预处理的时候打开了iostream这个文件,并将其代码复制到了main.cpp中,因此main.obj文件会如此庞大。我们可以通过以下方式验证。
在这里插入图片描述
这样在编译后就不会生成.obj文件,而是.i文件。重新编译两个.cpp文件。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以很清楚的看到test.i里的代码量很少,也就我们所写的那一部分,而main.i里所包含的东西已经多到不可思议了,因为它将iostream文件里的全部内容拷贝到了main.cpp中。

下面这个例子更能说明#include预处理命令,它的本质其实就是单纯的将它所包含的那个文件里的所有东西复制黏贴到.cpp中。
首先将属性里的选项改为否,这样才会生成.obj文件。
在这里插入图片描述
将test.cpp中的大括号删掉一半,并使用ctrl + f7编译。
在这里插入图片描述
添加一个头文件brace.h,且头文件里只有一个“}”。
在这里插入图片描述
在test.cpp里加上#include“brace.h”并使用ctrl + f7编译。
在这里插入图片描述
错误消失了,将属性选项改为是,再次编译后去文件目录里查看test.i文件。
在这里插入图片描述
可以看见#include“brace.h”将它里面的“}”复制黏贴到了test.cpp里相应的位置。
因此,#include的实质就是将它所包含的头文件里的所有的代码全部复制到.cpp文件中。

1、2 宏定义#define的替换

在这里插入图片描述
在这里插入图片描述
可以看到每一个.cpp里的INTTTT都被自动换成了int。

1、3 条件编译指令

在这里插入图片描述
在这里插入图片描述
因为条件#if 1为真,所以它所包含的代码在预编译后依然保存了下来。
在这里插入图片描述
在这里插入图片描述
因为#if 0为假,所以在预编译结束后,它所包含的代码就被隐藏了。

2、编译

当预处理结束后编译器就会创建一个抽象语法树,并通过这个抽象语法树开始实际生成可被cpu执行的机器代码。
让我们来看看编译完成后的test.obj里究竟有什么东西。
在这里插入图片描述
使用vs2022打开test.obj
在这里插入图片描述
我们可以看到一大堆二进制的机器码,这是计算机实际能运行的代码,但对我们来说完全不可读,我们可以通过vs2022来将其变成我们能够阅读的汇编语言。
在这里插入图片描述
再次使用ctrl + f7对test.cpp进行编译了后我们可以在文件目录里找到test.asm,这就是汇编语言程序,使用vs2022将其打开。
在这里插入图片描述
调用test函数
?test@@YAHHH@Z PROC ; test, COMDAT
这个并不是乱码而是函数签名,在一个工程中每个函数的签名都是独一无二的,这样才能在链接阶段找到。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值