C++编译过程

news/2024/11/28 23:35:14/

How the C++ Compiler works?

文章目录

  • How the C++ Compiler works?
    • compiling
    • Examples
    • 总结
      • 欢迎关注公众号【三戒纪元】

通过编程,是的text程序编程可执行文件,基本上主要有2个操作发生:

  • compiling 编译
  • linking 链接

compiling

C++ 编辑器要做的就是把文本变成中间格式——obj,然后obj们会被传入到linking,linking会做所有linking的事。

编译期要做的几件事:

  • pre-process 预处理代码。所有预处理语句会在那时被评估。常见的预处理语句有:include, define, if和ifdef

    include 预处理语句很简单,预处理时会打开include的文件,读取所有内容,然后粘贴进我们引用的 #include的文档中。

    如果我们有2个文件:

    EndBrace.h

    }
    

    Math.cpp文件

    int Multipy(int a, int b) {int result = a * b;return result;
    #include "EndBrace.h"
    

    此时编译2个文件,会发现能够编译成功,就是因为预处理时将 }放到了Math.cpp文件中的#include "EndBrace.h"处。

    预编译一下看下结果:

    (base) randy@SanJieJiYuan:~/compiler$ gcc -E EndBrace.h Math.cpp
    # 1 "EndBrace.h"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "EndBrace.h"
    }
    # 1 "Math.cpp"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "Math.cpp"
    int Multipy(int a, int b) {int result = a * b;return result;
    # 1 "EndBrace.h" 1
    }
    # 4 "Math.cpp" 2
    
  • tokenizing 标记解释 和 parsing 解析阶段:将C++ 文本处理处理成编译器能懂和处理的语言。创建叫做 abstract syntax tree(抽象语法树),就是以抽象语法树的形式表达代码,这是CPU会处理的机器码。

    可以打开生成的 obj文件看看里面其实写的已经是二进制数据了,只不过通过16进制表示出来。

    编译出可以看出来的汇编指令,这是计算机处理的指令:

    (base) randy@SanJieJiYuan:~/compiler$ gcc -o randy.asm -S Math.cpp
    (base) randy@SanJieJiYuan:~/compiler$ cat randy.asm .file   "Math.cpp".text.globl  _Z7Multipyii.type   _Z7Multipyii, @function
    _Z7Multipyii:
    .LFB0:.cfi_startprocendbr64pushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6movl    %edi, -20(%rbp)movl    %esi, -24(%rbp)movl    -20(%rbp), %eaximull   -24(%rbp), %eaxmovl    %eax, -4(%rbp)movl    -4(%rbp), %eaxpopq    %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
    .LFE0:.size   _Z7Multipyii, .-_Z7Multipyii.ident  "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0".section        .note.GNU-stack,"",@progbits.section        .note.gnu.property,"a".align 8.long    1f - 0f.long    4f - 1f.long    5
    0:.string  "GNU"
    1:.align 8.long    0xc0000002.long    3f - 2f
    2:.long    0x3
    3:.align 8
    4:
    

编译器的工作就是把代码转化为 constant data(常数资料),或者是instructions(指令)。同时会得到其他数据,比如某个地方存储着所有的 constant variables(常数变量)

编译器会为每个函数制作1个函数签名,由各种特殊字符和函数名组成,当程序编译时,编译器会通过查找函数签名将它们linking起来。当调用函数时,编译器就会生成1个call 指令。

Examples

建立1个Log.cpp 文件和Main.cpp文件

Log.cpp

#include<iostream>void Log(const char* message) {std::cout << message << std::endl;
}

Main.cpp

#include <iostream>void Log(const char* message);int main() {Log("Hello Randy!");std::cin.get();
}

编译不linking

g++ -c  Log.cpp Main.cpp
(base) randy@SanJieJiYuan:~/compiler$ ls
Log.cpp  Log.o  Main.cpp  Main.o

项目里的每个cpp,都会被编译器编译成一个obj,这些cpp文件也叫 translation unit(编译单元)

.
├── Log.cpp
├── Log.o
├── Main.cpp
└── Main.o-rw-rw-r-- 1 qiancj qiancj   92 613 23:10 Log.cpp
-rw-rw-r-- 1 qiancj qiancj 2904 613 23:11 Log.o
-rw-rw-r-- 1 qiancj qiancj  112 613 23:06 Main.cpp
-rw-rw-r-- 1 qiancj qiancj 2752 613 23:11 Main.o

这里我们看到cpp文件产生的obj文件远远大于原来的cpp文件大小,因为原始的cpp文件中均包含 #include<iostream>,包含的这个头文件很大,造成了最终编译出的obj文件也很大。

看看预处理后的文件,前面大部分都是 iostream 中的代码,因为 iostream 也会include 其他文件,因此文件会很大很大。

如果1个cpp文件包含其他cpp文件,则这些包含的文件整体就是1个编译单元,如果诸多cpp文件互不包含,则每个cpp文件就是1个编译单元。因此1个 cpp文件与1个编译单元不等同。

本质上你得意识到,C++根本不在乎文件,文件这种东西在c++里不存在,文件只是用来给编译器提供源码的某种方法

举个例子,java中 class(类)名必须跟文件夹相同,而文件结构也得跟package一样。之所以这样,因为java需要某些文件的存在,C++完全不是这回事。

C++中默认定义头文件以 .h 结尾,代码实现文件以 .cpp 结尾,就是告诉编译器以C++的方式编译。

总结

编译器拿到源文件,生成1个包含机器语言和其他我们定义的常数数据的obj文件,然后将它们链接成1个包含所有需要运行的机器代码的可执行文件。


欢迎关注公众号【三戒纪元】


http://www.ppmy.cn/news/500664.html

相关文章

IComponent2 Interface 学习

Solidworks学习笔记-链接Solidworks 在此基础上学习 允许访问程序集中的组件。 属性 NameDescription备注ComponentReferenceGets or sets a component reference for this component. 获取或设置此组件的组件引用。IMaterialPropertyValuesGets or sets the material pro…

IDrawingComponent Interface 学习

Solidworks学习笔记-链接Solidworks 在此基础上学习 属性 NameDescription备注ComponentGets the referenced component for this drawing component. 获取此绘图组件的引用组件。LayerGets or sets the name of the layer on which the component resides in the view. 获…

C# SolidWorks二次开发-工程图-更换工程图图纸格式/模板

这两天有朋友提问&#xff0c;怎么更换工程图模板。 正好晚上还能挤点时间&#xff0c;就来写一篇文件解答一下。 首先&#xff0c;更换工程图模板&#xff0c;你需要知道手动怎么修改。 如下图&#xff0c;我这个没有模板&#xff0c;只有个纸张大小。 对着视图&#xff0c;右…

C# SolidWorks二次开发---工程图中心标记(Center Marks)

工程图的中心标记 作为一个不专业的制图人员&#xff0c;我就不解释中心标记是什么了。大家自己看Solidworks的官方帮助说明(好像不应该放英文的&#xff0c;大家都看不懂了 )。 就是这么个东东。 我自己画了一个非常复杂的图纸&#xff0c;创建主视图的时候好像就自动增加了…

PDM中的自定义属性映射

在PDM中需要在数据卡中反馈出文件的一些属性信息&#xff0c;使得用户在不打开文件的情况下可以快速了解此文件的属性信息&#xff0c;所以就需要实施的过程中在PDM后台做好属性映射&#xff0c;此文章主要讲述SOLIDWORKS文件、Excel文件、Word文档的属性映射。 SOLIDWORKS文件…

SOLIDWORKS 如何重用DWG格式图纸

经常有工程师咨询DWG图纸在SOLIDWORKS软件里如何使用&#xff0c;其实这涉及到DWG图纸在SOLIDWORKS软件里的重用问题&#xff0c;SOLIDWORKS支持对DWG图纸的重用&#xff0c;常用的有三种方法&#xff1a; 1、作为原始DWG图纸查看 作为原始DWG图纸查看是指使用SOLIDWORKS软件…

DATAKIT CrossManager 2022.4 Crack

CrossManager 是一款独立软件&#xff0c;可让您转换大多数 CAD 格式的文件。 使用 Cross Manager&#xff0c;您只需选择一个或多个 CAD 文件&#xff0c;即可将它们自动翻译成您想要的格式。 DATAKIT CrossManager是一款独立软件&#xff0c;可让您转换大多数 CAD 格式的文件…

数领科技|学会用低版本solidworks软件打开高版本sw文件

对各位使用solidworks进行设计的工程师而言,在工作中我们常常会遇到这样的情况,当我们将自己做好的SOLIDWORKS模型发给别人时,却因为对方的SOLIDWORKS版本较低,而打不开模型文件。在这种时候,我们通常需要先将SOLIDWORKS模型转换成中间格式(igs、stp等),然后对方就可以…