C++编译过程

news2024/9/30 5:27:40

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_startproc
            endbr64
            pushq   %rbp
            .cfi_def_cfa_offset 16
            .cfi_offset 6, -16
            movq    %rsp, %rbp
            .cfi_def_cfa_register 6
            movl    %edi, -20(%rbp)
            movl    %esi, -24(%rbp)
            movl    -20(%rbp), %eax
            imull   -24(%rbp), %eax
            movl    %eax, -4(%rbp)
            movl    -4(%rbp), %eax
            popq    %rbp
            .cfi_def_cfa 7, 8
            ret
            .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.coloradmin.cn/o/670581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VXLAN:数据中心网络的未来

概要 随着云计算和虚拟化技术的快速发展&#xff0c;数据中心网络正面临着越来越大的挑战。传统的网络架构在适应大规模数据中心的需求方面存在一些限制&#xff0c;如扩展性、隔离性和灵活性等方面。为了克服这些限制&#xff0c;并为数据中心网络提供更好的性能和可扩展性&am…

【好书精读】网络是怎样连接的 之 连接服务器

&#xff08;该图由AI制作 学习AI绘图 联系我&#xff09; 目录 1 连接是什么意思 1.1 连接实际上是通信双方交换控制信息 2 负责保存控制信息的头部 2.1 客户端与服务器之间交换的控制信息 连接操作的实际过程 1 连接是什么意思 创建套接字之后 &#xff0c; 应用程序 …

Selenium教程__使用execute_script执行JavaScript(11)

selenium的包含的方法已能完全满足UI自动化&#xff0c;但是有些时候又不得不用到执行JS的情况&#xff0c;比如在一个富文本框中输入1W个字&#xff0c;使用send_keys方法将经历漫长的输入过程&#xff0c;如果换成使用JS的innerHTML方法就能够很快的完成输入。 selenium执行…

Shell 函数实现Go语言多版本管理轻量级方案

现有的工具方案 https://github.com/moovweb/gvmhttps://github.com/voidint/g 我的方案 优点&#xff1a; 原生&#xff1a;基于 go 语言本身支持多版本的能力实现&#xff0c;可以下载任何官方发布的版本简单&#xff1a;shell 函数实现&#xff0c;直接集成到 bashrc 或…

软件测试技能,JMeter压力测试教程,HTTP Cookie管理器(四)

目录 前言 一、场景案例 二、HTTP Cookie管理器 三、302 重定向 前言 Web网站的请求大部分都有cookies&#xff0c;jmeter的HTTP Cookie管理器可以很好的管理cookies 我用的 jmeter5.1 版本&#xff0c;直接加一个HTTP Cookie管理器放到请求的最前面&#xff0c;就可以自…

用docker搭建selenium grid分布式环境实践

目录 前言&#xff1a; selenium jar包直接启动节点 用docker命令直接启动 docker-compose 启动 Hub和node在一台机器上 Hub和node不在一台机器上 遗留问题 总结 前言&#xff1a; Selenium是一个流行的自动化测试工具&#xff0c;支持多种编程语言和多种浏览器。Sele…

【微服务架构演进】一文读懂单片到微服务架构的模式和最佳实践

在本文中&#xff0c;我们将学习如何使用设计模式、原则和最佳实践来设计微服务架构。我们将使用正确的架构设计模式和技术。 在本文结束时&#xff0c;您将了解如何在微服务分布式架构上设计系统以实现高可用性、高可扩展性、低延迟和对网络故障的弹性&#xff0c;从而处理数百…

学习Spring之声明式事务

什么是事务&#xff1f; 一个业务有一组操作&#xff0c;要么都成功&#xff0c;要么都失败 事务的四大特性&#xff1a;ACID A 原子性&#xff1a;一组操作&#xff0c;要么都成功&#xff0c;要么都失败 C 一致性 &#xff1a;事务的前后要保证事务的一致性 I 隔离性 &…

QLabel的使用

QLabel介绍 QLabel 是 Qt 框架中的一个控件类&#xff0c;用于显示文本或图像。它可以在窗口或其他容器中显示静态文本&#xff0c;并且可以根据需要设置格式、对齐方式和尺寸。 主要作用如下&#xff1a; 显示文本内容&#xff1a;QLabel 可以显示文字内容&#xff0c;可以…

【每天40分钟,我们一起用50天刷完 (剑指Offer)】第二天

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

Spring Boot 中使用 @EventListener 注解监听事件

Spring Boot 中使用 EventListener 注解监听事件 Spring Boot 是一个流行的 Java Web 框架&#xff0c;它提供了丰富的功能和工具来简化开发人员的工作。其中一个非常有用的功能是事件监听器。在 Spring Boot 中&#xff0c;我们可以使用 EventListener 注解来监听事件&#x…

一天时间完成Python入坑(开发环境搭建、excel解析、exe打包三步走)

0.为什么要入坑Python 早就知道Python好&#xff0c;Python妙&#xff0c;Python用起来呱呱叫。工作上一直没有什么用得上Python的必要性&#xff0c;就一直没有接触&#xff0c;本次终于来了机会&#xff1a;【图新地球桌面端要对外开放Python API】&#xff0c;开放图新地球的…

【mars3d】Cesium实现雷达放射波

Cesium实现雷达放射波 1、雷达放射波 先看效果图 说明&#xff1a;使用的是mars3d框架&#xff0c;原生的Cesium实现方式可以绕道~ 实现方式&#xff1a; <template><div id"mars3dContainer"></div> </template><script setup> i…

Fiddler抓包基础使用

目录 一、设置抓谷歌浏览器https数据包 1、选中以下选项即可 2、若是选中后还是未抓到HTTPS数据包&#xff0c;则可进行以下操作 二、设置抓取Firefox浏览器HTTPS数据包 1、Firefox的代理需设置系统代理&#xff0c;设置→高级→网络设置&#xff0c;设置为系统代理&#…

【深度学习】5-3 与学习相关的技巧 - Batch Normalization

如果为了使各层拥有适当的广度&#xff0c;“强制性”地调整激活值的分布会怎样呢&#xff1f;实际上&#xff0c;Batch Normalization 方法就是基于这个想法而产生的 为什么Batch Norm这么惹人注目呢?因为Batch Norm有以下优点&#xff1a; 可以使学习快速进行(可以增大学习…

广工赢清华,炸裂!

去年2022年广工对阵清华&#xff0c;我在知乎写了文章 清华赢球靠的是广东第一高中生邹阳和2022届CBA状元王岚嵚。 比分焦灼的第四节关键时刻&#xff0c;邹阳在左角底线持球高高举起篮球&#xff0c;那个球的弧度非常高&#xff0c;皮球以稳稳的抛物线弧度掉入篮筐。 之后&…

Python基础(21)——Python函数实战、递归、lambda、高阶函数

Python基础&#xff08;21&#xff09;——Python函数实战、递归、lambda、高阶函数 文章目录 Python基础&#xff08;21&#xff09;——Python函数实战、递归、lambda、高阶函数目标一. 应用&#xff1a;学员管理系统1.1 系统简介1.2 步骤分析1.3 需求实现1.3.1 显示功能界面…

Streamlit基础教程

streamlit是什么 streamlit是一个开源的python库&#xff0c;它能够快速的帮助我们创建定制化的web应用&#xff0c;而且还非常便于和他人分享&#xff0c;特别是在机器学习和数据科学领域。整个过程不需要你了解任何前端的知识&#xff0c;包括html、css、javascript等&#x…

Vue3 计算属性和侦听器实战(computed、watch)——简易点餐页面

文章目录 &#x1f4cb;前言&#x1f3af;项目介绍&#x1f3af;项目创建&#x1f3af;代码分析&#x1f3af;完整代码&#xff08;含 CSS 代码&#xff09;&#x1f4dd;最后 &#x1f4cb;前言 这篇文章记录一下 Vue3 计算属性和侦听器 &#xff08;computed、watch&#xf…

网络安全自学能学会吗?网络安全如何学习

网络安全是近年来的热门工作&#xff0c;吸引了许多小伙伴开始学习网络安全知识。那么我们应该如何学习网络安全呢&#xff1f;这是一个很多人都在考虑的问题。网络安全可以自学吗&#xff1f;自学网络安全能不能学会&#xff1f; 无论什么知识都是自学的&#xff0c;只是说每…