最好的C++教程 —2.how c++ complier works

C++编译器的工作原理

window下编译器只负责将源文件转换为中继格式obj

1.预处理

所有的preprocessor语句将会在这个阶段进行评估

2.tokenizing and parsing阶段(具体参考编译原理)

创建抽象语法分析树

3.本质

编译器的工作将代码转化为 constant data(常数资料) or instruction(指令)
其实从编译原理的角度就是 语法树和符号表

特性

和java相比,C++不关心文件,java类名和文件名必须相同,文件结构也要和package相同,而C++文件只是提供源码的方法,文件没有任何意义,只是由后缀名告诉编译器这是.c要按c编译,这是.h头文件,你也可以用一个没有任何意义的后缀,只要你在代码中告诉编译器请按cpp进行编译

头文件的工作例子

我们新建一个EndBrace.h
内容仅仅为一个右括号
在这里插入图片描述
我们删除log.cpp的右括号,编译失败了
在这里插入图片描述
我们修改为下面的样子

#include <iostream>
void log(const char* message)
{
    std::cout << message << std::endl;
#include "EndBrace.h"

在这里插入图片描述
编译成功,可见头文件仅仅起到一个内容复制粘贴的作用
为了更加形象,我们设置预处理到文件,看看究竟发生了什么
在这里插入图片描述
为了简单我新建了一个math.cpp(不包含iostream,因为你会发现它足足有5万多行)
内容如下

void math(const char* message)
{
    
#include "EndBrace.h"

预编译生成的.i文件内容如下
在这里插入图片描述
可见预处理后仅仅将复制过来而已
至于#line语句仅仅是改变行数和文件名而已可以不理会

#define 的工作(宏定义:替换)

#define INTEGER int
INTEGER math(const char* message)
{
	INTEGER x = 0;
	return x;
}

编译后查看.i文件

#line 1 "C:\\Users\\Aimer\\source\\repos\\class2.2\\class2.2\\math.cpp"

int math(const char* message)
{
	int x = 0;
	return x;
}

仅仅将INTEGER替换为 int

#if的工作

#define INTEGER int
#if 1
INTEGER math(const char* message)
{
	INTEGER x = 0;
	return x;
}
#else
void math(const char* message)
{
INTEGER x = 0;

}
#endif

编译后查看.i文件
在这里插入图片描述
#if 后面为真(非0)则注释掉#else后的语句块
否则注释掉#if后的语句块
#if对于注释掉大块语句与/**/相比有着十分方便的使用
你只需要修改#if 后的条件即可方便的选择使用或注释掉某语句块
和if else的不同:
if else会直接编译执行,而#if是编译器指令,其作用是告诉编译器,有些语句行希望在条件满足时才编译。

.obj文件里是什么

取消预处理到文件,重新编译,查看math.obj
在这里插入图片描述
可见是大量的机器码,显然机器码对于人类而言可读性几乎没有,我们想办法转为可读性强一点的汇编代码
在这里插入图片描述
编译查看

在这里插入图片描述
编译器优化
选择最大优化
在这里插入图片描述
编译错误
在这里插入图片描述
设置基本运行检查为默认
在这里插入图片描述
编译后生成的汇编代码量明显减少
我们修改代码没有任何输入,单纯计算两个常量的和

int math()
{

return 5+8;
}

查看汇编代码
在这里插入图片描述
发现没有进行加操作,仅仅只是将13push
这涉及到了常量折叠(constant folding),没有必要在运行时去计算两个常量的和,在编译阶段就已经计算完成,是编译优化的一部分
关于常量折叠的详情可以点击上方超链接,这里就不详细讲解。

我们再测试一个例子

const char* log(const char* message)
{
    return message;
}
int math()
{
    log("hello");
return 5+8;
}

log只是返回了message实际上什么也没干
无优化下的汇编代码
在这里插入图片描述
?log@@YAPBDPBD@Z涉及函数签名来独一无二地定义你的函数,我们在linker章节再讲,linker会通过函数签名联系多个obj之间的函数
我们开启最大优化速度
在这里插入图片描述
call语句完全消失了,因为编译器检测到我们的函数实际上什么也没干,直接就优化掉了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值