The Cherno C++笔记02

目录

Part 06 How the C++ Compiler Works

1.编译过程

2.C++并不关心文件

3.翻译单元(Translation Unit)

4. 实际用代码感受一下编译过程

4.1 预处理

4.1.1 预处理的本质

4.1.2 预处理后的.i文件

4.1.3 骚操作

4.2 .asm文件(汇编语言源文件)

4.2.1 直观感受优化

4.2.2 常量折叠(Constant Folding)


Part 06 How the C++ Compiler Works

1.编译过程

我们在编译软件上写的内容,实际上就是文本,那从文本到可执行的程序,中间需要经过两步,编译和链接。编译就是将文本转化为.obj后缀的目标文件。

编译又可以分为几个步骤:

①预处理(Preprocessing)

②词法分析(Lexical Analysi)

③语法分析(Syntax Analysis)

④语义分析(Semantic Analysis)

⑤优化(Optimization)

⑥代码生成(Code Generation)

我们可以用一个简单的例子来直观感受一下每个过程

源代码:

#include <stdio.h>int main() {int a = 5;int b = 7;int sum = a + b;printf("Sum is: %d\n", sum);return 0;
}

词法分析生成词法单元(Tokens)

Keyword: include
Identifier: <stdio.h>
Keyword: int
Identifier: main
Punctuation: (
Punctuation: )
Punctuation: {
Keyword: int
Identifier: a
Operator: =
Number: 5
Punctuation: ;
...

语法分析生成抽象语法树(AST)

Program
|
└── Function: main├── Declaration: int a├── Assignment: a = 5├── Declaration: int b├── Assignment: b = 7├── Declaration: int sum├── Assignment: sum = a + b├── Function Call: printf│   ├── String: "Sum is: %d\n"│   ├── Argument: sum└── Return: 0

语义分析:

  • 语义信息:
    • 类型检查通过,变量和函数引用有效。
    • 符号表记录了变量的类型和位置。

优化(Optimization):

int a = 5;
int b = 7;
int sum = a + b;
printf("Sum is: %d\n", sum);
return 0;

代码生成(Code Generation)

MOV a, 5
MOV b, 7
ADD sum, a, b
PRINT "Sum is: %d\n", sum
HALT

转成obj机器码


2.C++并不关心文件

这主要是跟Java做对比

在Java中,一个源代码文件通常对应一个类,且文件名与类名相同,并以 .java 为扩展名。而在C++中:源代码可以分布在多个文件中,每个文件独立地包含了一部分程序的实现。这些文件可以包含函数、类、变量的定义和实现等。默认情况下编译器看到.h文件会将其作为头文件处理,见到.cpp文件会将其作为源文件处理。你可以改变它,不具有强制性。
总而言之:

在Java中,文件名与类名的匹配是强制性的,而且有严格的规范。这种规范有助于提高代码的可读性和可维护性,但也限制了一定的灵活性。

在C++中,虽然有一些约定(例如使用.cpp作为源文件的扩展名),但这些并非强制性规定。C++更加注重灵活性和兼容性,允许开发者使用不同的扩展名或者甚至没有扩展名。这种灵活性允许开发者更自由地组织和命名源文件,但也可能导致一些不规范的实践。


3.翻译单元(Translation Unit)

在编译过程中被处理的最小单元。在C++中一个源文件和一个头文件通常就是一个翻译单元。一个翻译单元作为编译器的输入,经过编译过程后生成一个目标文件,然后多个目标文件可以被链接在一起形成最终的可执行程序。


4. 实际用代码感受一下编译过程

4.1 预处理

4.1.1 预处理的本质

预处理其实就是复制粘贴头文件的内容

我们写两个源文件感受一下:

math.cpp(没有包含任何头文件)

int Multiply(int a, int b)
{return a + b;
}

Log.cpp(包含iostream头文件)

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

然后我们单独编译(Ctrl+F7)

得到两个obj文件

大小差距很大,造成这种现象的原因就是包含头文件,预处理会把头文件的内容全部复制到Log.cpp中来。

4.1.2 预处理后的.i文件

.i 文件是指预处理后的源文件。在C和C++编译过程中,预处理器会对源文件进行处理,展开宏、处理条件编译指令等,并生成一个经过预处理的中间文件。这个中间文件的扩展名通常是.i

我们可以通过更改下面的设置来让他生成预处理后的.i文件


对Main.cpp文件预处理

#include <iostream>void Log(const char* message);int main()
{Log("Hello World!");//用Log函数实现打印的功能std::cin.get();
}

文本编辑器打开Main.i文件

我们会直观的发现这个现象

4.1.3 骚操作

利用这个特点我们可以实现一些骚操作

建一个只有一个结束大括号的头文件

EndBrace.h

}

然后将原本.cpp文件中的结束大括号改成#include “EndBrace.h”(自己建立的头文件用双引号)还能编译成功吗?

Math.cpp(替换)

int Multiply(int a, int b)
{return a + b;
#include "EndBrace.h"

成功!

打开生成的.i文件

还可以利用宏定义

#define (被替换的内容) (替换后的内容)

#define Age 18 就是在预处理的时候,把代码里面的Age全部替换成18

Math.cpp(替换)

#define INTEGER int
INTEGER Multiply(INTEGER a, INTEGER b)
{return a + b;
}

成功!

打开生成的.i文件

#if 预处理指令用于条件编译。它允许根据指定的条件来选择性地包含或排除部分代码。

Math.cpp(替换)

#if 1
int Multiply(int a, int b)
{return a + b;
}
#endif

打开生成的.i文件


Math.cpp(替换)

#if 0
int Multiply(int a, int b)
{return a + b;
}
#endif

v打开生成的.i文件

4.2 .asm文件(汇编语言源文件)

关闭刚才的设置

更改汇编语言文件输出

这里我们可以看到源代码的汇编语言格式

4.2.1 直观感受优化

Debug版本总共有253行

如果我们改一下Debug版本的设置为

这个时候我们继续运行编译

只有177行

4.2.2 常量折叠(Constant Folding)

常量折叠(Constant Folding)是编译器在编译时对表达式中的常量进行计算和简化的过程。在这个过程中,编译器会尽可能地将表达式中的常量计算出结果,以减少运行时的开销。

改一下Math.h

int Multiply()
{return 2*5;
}

编译,并查看生成的汇编文件.asm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/240370.shtml

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

相关文章

安装nodejs,配置环境变量并将npm设置淘宝镜像源

安装nodejs并将npm设置淘宝镜像源 1. 下载nodejs 个人不喜欢安装包&#xff0c;所以是下载zip包的方式。这里我下载的node 14解压包版本 下载地址如下&#xff1a;https://nodejs.org/dist/v14.15.1/node-v14.15.1-win-x64.zip 想要其他版本的小伙伴去https://nodejs.org/di…

C++ 检测 是不是 com组件 的办法 已解决

在日常开发中&#xff0c;遇到动态库和 com组件库的调用 无法区分。检测是否com组件的办法 在头部文件&#xff0c;引入文件 如果能编译成功说明是 com组件&#xff0c;至于动态库如何引入&#xff0c;还在观察中 最简单办法 regsvr32 TerraExplorerX.dll 是com 组件 regs…

LLaMA开源大模型源码分析!

Datawhale干货 作者&#xff1a;宋志学&#xff0c;Datawhale成员 花了一晚上照着transformers仓库的LLaMA源码&#xff0c;把张量并行和梯度保存的代码删掉&#xff0c;只留下模型基础结构&#xff0c;梳理了一遍LLaMA的模型结构。 今年四月份的时候&#xff0c;我第一次接触…

OpenAI 疑似正在进行 GPT-4.5 灰度测试!

‍ 大家好&#xff0c;我是二狗。 今天&#xff0c;有网友爆料OpenAI疑似正在进行GPT-4.5灰度测试&#xff01; 当网友询问ChatGPT API调用查询模型的确切名称是什么时&#xff1f; ChatGPT的回答竟然是 gpt-4.5-turbo。 也有网友测试之后发现仍然是GPT-4模型。 这是有网友指…

自动化测试架构设计必会知识点——对核心业务进行封装复用(附Java源码)

随着UI自动化测试工具可选性越来越多&#xff0c;工具也越来越稳定&#xff0c;前几年关于自动化测试架构设计的概念逐渐淡化&#xff0c;但是做自动化测试最重要的两点—— PO设计模式和核心业务的封装复用大家还是必须掌握的&#xff0c;前面的文章我已经介绍了什么是PO设计模…

基于 Sentry 的前端监控系统搭建(Linux)

一、前言 随着技术这几年的发展与沉淀&#xff0c;线上数据指标监控也变得尤为重要&#xff0c;研发人员和运营人员需要对线上的产品指标有所感知&#xff0c;同时风险也需要及时暴露&#xff0c;很多公司开始自建监控系统&#xff0c;但对于一些定制化要求不是特别高的团队&a…

网络爬虫之Ajax动态数据采集

动态数据采集 规则 有时候我们在用 requests 抓取页面的时候&#xff0c;得到的结果可能和在浏览器中看到的不一样&#xff0c;在浏览器中可以看到正常显示的页面教据&#xff0c;但是使用 requests 得到的结果并没有&#xff0c;这是因为requests 获取的都是原始的 HTML 文档…

(1)(1.9) MSP (version 4.2)

文章目录 前言 1 协议概述 2 配置 3 参数说明 前言 ArduPilot 支持 MSP 协议&#xff0c;可通过任何串行端口进行遥测、OSD 和传感器。这样&#xff0c;ArduPilot 就能将遥测数据发送到 MSP 兼容设备&#xff08;如大疆护目镜&#xff09;&#xff0c;用于屏幕显示&#x…

银河麒麟v10 安装mysql 8.35

银河麒麟v10 安装mysql 8.35 1、卸载mariadb2、下载Mysql安装包3、安装Mysql 8.353.1、安装依赖包3.2、安装Mysql3.3、安装后配置 1、卸载mariadb 由于银河麒麟v10系统默认安装了mariadb 会与Mysql相冲突&#xff0c;因此首先需要卸载系统自带的mariadb 查看系统上默认安装的M…

MyBatis动态SQL中if,where,set,trim四种标签的使用和联系

目录 MyBatis动态SQL中if&#xff0c;where&#xff0c;set&#xff0c;trim四种标签的使用和联系1、先介绍trim标签以下是trim标签中涉及到的属性&#xff1a; 2、使用trim标签或where标签去除多余的and关键字3、使用trim标签或set标签去除多余的逗号 MyBatis动态SQL中if&…

前端常用的开发工具

前端常用的开发工具&#x1f516; 文章目录 前端常用的开发工具&#x1f516;1. Snipaste--截图工具2. ScreenToGif--gif图片录制3. Typora--Markdown编辑器4. notepad--文本代码编辑器5. uTools--多功能工具6. EV录屏--录屏软件7. Xmind--思维导图8. Apifox -- 接口调试9. Tor…

【大数据】NiFi 中的 Controller Service

NiFi 中的 Controller Service 1.Service 简介1.1 Controller Service 的配置1.1.1 SETTING 基础属性1.1.2 PROPERTIES 使用属性1.1.3 COMMENT 页签 1.2 Service 的使用范围 2.全局参数配置3.DBCPConnectionPool 的使用样例4.在 ExcuseGroovyScript 组件中使用 Service 1.Servi…

记一次 Nginx 调参的踩坑经历

最近在基于SSE&#xff08;Server Sent Events&#xff09;做服务端单向推送服务&#xff0c;本地开发时一切顺利&#xff0c;但是在部署到预发环境时就碰到1个很诡异的问题&#xff0c;这里需要简单介绍下我们的整体架构&#xff1a; 整体架构 可以看到所有的请求都会先到统一…

2024 年 22 款顶级免费数据恢复软件比较 [Windows 和 Mac]

适用于 Windows 和 Mac 用户的最佳数据恢复软件下载列表和比较&#xff0c;可快速恢复丢失的数据、已删除的文件、照片或格式化的分区数据&#xff1a; 数据恢复软件是一种从任何存储介质恢复丢失文件的应用程序。它可以恢复由于病毒攻击、硬盘故障或任何其他原因而意外删除或…

NIO的实战教程(简单且高效)

1. 参考 建议按顺序阅读以下三篇文章 为什么NIO被称为同步非阻塞&#xff1f; Java IO 与 NIO&#xff1a;高效的输入输出操作探究 【Java.NIO】Selector&#xff0c;及SelectionKey 2. 实战 我们将模拟一个简单的HTTP服务器&#xff0c;它将响应客户端请求并返回一个固定的…

Maven核心概念

1 Maven工程的GAVP Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写&#xff0c;其中前三个是必要的&#xff0c;而 Packaging 属性为可选项。 这四个属性主要为每个项目在maven仓库中做一个标识&#xff0c;方便项目之间相互引用。 GAV G 即…

桶装水送水小程序:提升服务质量的利器

随着移动互联网的发展&#xff0c;越来越多的消费者通过手机在线购物和订购商品。如果你是一名桶装水供应商&#xff0c;想要拓展线上业务&#xff0c;那么开发一个桶装水微信小程序将是一个明智的选择。本文将指导你从零开始开发一个桶装水微信小程序&#xff0c;让你轻松完成…

Coze在手,GPTsDALLE免费用

1. 关于Coze Coze 是一个应用程序编辑平台&#xff0c;旨在开发下一代人工智能聊天机器人。 你可以使用无代码创建各种类型的聊天机器人&#xff0c;并将其部署到各种社交平台和消息应用程序。 链接: Coze 2. Coze的特点 Coze有5个特点。下面由我来详细介绍一下&#xff01;…

高级数据结构 <二叉搜索树>

本文已收录至《数据结构(C/C语言)》专栏&#xff01; 作者&#xff1a;ARMCSKGT 目录 前言正文二叉搜索树的概念二叉搜索树的基本功能实现二叉搜索树的基本框架插入节点删除节点查找函数中序遍历函数析构函数和销毁函数(后序遍历销毁)拷贝构造和赋值重载(前序遍历创建)其他函数…

蓝牙物联网与嵌入式开发如何结合?

蓝牙物联网与嵌入式开发可以紧密结合&#xff0c;以实现更高效、更智能的物联网应用。以下是一些结合的方式&#xff1a; 嵌入式开发为蓝牙设备提供硬件基础设施和控制逻辑&#xff1a;嵌入式系统可以利用微处理器和各种外设组成的系统&#xff0c;为蓝牙设备提供硬件基础设施和…