C++ 知识要点
C++ 的编译过程
编译的基本步骤
Step1:Call a preprocessor, like cpp. 预处理阶段,将各类include/宏展开;
Step2:Call an actual compiler, like cc or cc1; 编译阶段,语法检查,没问题以后生成汇编;
Step3:Call an assembler, like as. 汇编过程,将上面汇编代码转成二进制代码;
Step4:Call a linker, like ld; 将各个二进制代码进行链接,生成最终的程序;
preproccess(预处理)
预处理包括的内容大概有,复制粘贴#include文件内容,解析宏定义#define、#if、#ifend,以及常量的直接计算
以 #include 为例
#include的作用请看下例
假设目前项目存在 acc.h、Math.cpp 文件
acc.h,仅有一个符号内容而已
}
Math.cpp,一个简单的乘法函数
int Mutliply(int a, int b)
{
return a * b;
#include "acc.h"
上面这两段代码可以编译并且运行成功。由此可以看来#include的作用就是粘贴复制
不信的话我们可以看下预处理文件,visual studio 2022默认设置是不会生成预处理文件的,需要我们修改项目配置。右键项目,然后点击属性
对照图中内容进行配置,
预处理到文件 这项改为 YES
Ctrl + f7 编译一下,然后再到output目录中找到预处理文件
Math.i,不出意外 acc.h 中的内容被复制粘贴到了Math.cpp文件中
我们可以尝试更多案例,看看
#define 预处理之后是什么样的吧。语法 #define INTEGER int,表示会找到文件中 a 全部替换成 b,不要问我为什么写 INTEGER,如果你想的话你可以把 INTEGER 换成 “傻逼” 也是可以的
可以看到 预处理文件中的 INTEGER 全部被替换成了 int,同样在预处理阶段完成的事情还有很多,#if #ifend等等。
前面我们说到了,#include 就是复制粘贴,我们这里可以验证一下 main.cpp 文件。
main.cpp 文件内容
#include <iostream>
int main()
{
std::cout << "Holle Word" << std::endl;
std::cin.get();
}
预处理文件末尾内容,可以看到我么写的代码已经到了6w多行,前面都是 iostream 里面的代码
ok,现在我们来看一下obj文件内容。在此之前的 “预处理到文件” yes 设置改回 no。如果你设置了 yes, build将不会再产生 obj 文件。修改之后重新 ctrl + f7 编译生成obj文件
直接打开的话是二进制展示。很显然并没有什么卵用,我看不懂。
既然如此,得设置一下输出能看得懂的文件
按照上面动画设置,我们可以得到一个含有汇编内容的文件
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.33.31629.0
include listing.inc
INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES
msvcjmc SEGMENT
__E68C42ED_Math@cpp DB 01H
msvcjmc ENDS
PUBLIC ?Mutliply@@YAHHH@Z ; Mutliply
PUBLIC __JustMyCode_Default
EXTRN _RTC_InitBase:PROC
EXTRN _RTC_Shutdown:PROC
EXTRN __CheckForDebuggerJustMyCode:PROC
; COMDAT pdata
pdata SEGMENT
$pdata$?Mutliply@@YAHHH@Z DD imagerel $LN3
DD imagerel $LN3+64
DD imagerel $unwind$?Mutliply@@YAHHH@Z
pdata ENDS
; COMDAT rtc$TMZ
rtc$TMZ SEGMENT
_RTC_Shutdown.rtc$TMZ DQ FLAT:_RTC_Shutdown
rtc$TMZ ENDS
; COMDAT rtc$IMZ
rtc$IMZ SEGMENT
_RTC_InitBase.rtc$IMZ DQ FLAT:_RTC_InitBase
rtc$IMZ ENDS
; COMDAT xdata
xdata SEGMENT
$unwind$?Mutliply@@YAHHH@Z DD 025051601H
DD 01112316H
DD 0700a0021H
DD 05009H
xdata ENDS
; Function compile flags: /Odt
; COMDAT __JustMyCode_Default
_TEXT SEGMENT
__JustMyCode_Default PROC ; COMDAT
ret 0
__JustMyCode_Default ENDP
_TEXT ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; COMDAT ?Mutliply@@YAHHH@Z
_TEXT SEGMENT
math_a$ = 4
a$ = 256
b$ = 264
?Mutliply@@YAHHH@Z PROC ; Mutliply, COMDAT
; File E:\CppProject\cpp\cherno\Math.cpp
; Line 4
$LN3:
mov DWORD PTR [rsp+16], edx
mov DWORD PTR [rsp+8], ecx
push rbp
push rdi
sub rsp, 264 ; 00000108H
lea rbp, QWORD PTR [rsp+32]
lea rcx, OFFSET FLAT:__E68C42ED_Math@cpp
call __CheckForDebuggerJustMyCode
; Line 5
mov DWORD PTR math_a$[rbp], 10
; Line 6
mov eax, DWORD PTR a$[rbp]
imul eax, DWORD PTR b$[rbp]
; Line 7
lea rsp, QWORD PTR [rbp+232]
pop rdi
pop rbp
ret 0
?Mutliply@@YAHHH@Z ENDP ; Mutliply
_TEXT ENDS
END
汇编无疑是比二进制的内容容易看懂的多,至于汇编内容这边就不做解释了,看得懂的都懂。
好了全篇内容到这里就结束了,下一遍我会讲一下 linker 的简要内容!!