对于编译原理的理解

#编译原理
今天组长教育了一下整个程序的编译过程,感觉自己对于这块了解还是很少,有许多知识之前知道,现在忘记了,还有很多规则只是知道,但并不知道它为什么要这样写,所以再次记录一下,有什么问题或者错误希望大家在评论区提出。。。。

编译原理

如图
这里写图片描述

预编译阶段

在预编译阶段,发挥作用的是预处理器(CPP)。预处理器读取.cpp文件,对其中的伪指令(#开头的指令)和特殊符号进行处理,特别的,对#include指令进行递归处理,包含需要的头文件。
常见的伪指令有#define、#include""(包括你需要的头文件),在你的预处理器处理过后,会将你#include的头文件中的代码内容(不包括预处理的内容)替换到你的.cpp文件中,也会将你#define的内容替换,会选择你条件编译(#if #else #endif)的代码块等汇总成一个新的源文件。
预处理阶段还会将注释删除
添加行号和文件名标识,方便调试使用
特例:保留所有的#pragma指令,因为编译器需要使用
此时源程序还是文本文件。
###编译阶段
在这个阶段中,编译器(CC1)会进行语法分析、语义分析、词法分析、优化、将源文件转换为汇编语言,汇编语言还是文本文件,但CPU无法理解文本文件。
###汇编阶段
在这个阶段,发挥作用的是汇编器(AS),汇编器会将汇编语言翻译成机器语言,机器只会识别二进制,所以机器语言为二进制。window平台上是.obj文件,linux是.o文件,为可重定位的目标文件。
###链接阶段
这个阶段发挥作用的是连接器(LD),链接器会将所有的.obj文件链接到一起,成为可执行的.exe文件。链接时会将程序引用的库与自己生成的.obj文件一起链接成为可执行文件,这样的链接方式就叫做静态链接。但是存在一个问题,如果你的应用程序使用了很多库,静态链接会将所有的库链接到你的.obj文件中,最终形成很大的.exe程序,不利于以后程序的更新。所以就出现了动态链接。
动态链接,动态库在链接阶段不会被链接到.obj文件中,应该只是(我也不确定)将你用到的API的地址等一系列信息和你的.obj文件链接起来,形成.exe文件,在你的exe程序运行时才加载这个动态库文件,这样,就大大减少了你的应用程序的大小,方便更新等一系列优点。
###生成exe
这样,你的exe就生成了。
##注意点
###防止多重包含
在预处理阶段,你会经常看到#ifndef #define #endif。这是为了防止重复包含。在预处理器第一次处理这个头文件时,会#define一个宏,当其他文件再次包含这个头文件时,预处理器检测到这个宏,会直接跳过这段代码,这样就不会出现重复代码
###.h和.cpp文件
在编译成.obj文件时,一个.h和对应的.cpp会形成一个.obj文件,你的工程中如果有多个.h和.cpp文件,就会生成多个.obj文件,例如一个C_Object类的.h和.cpp文件将会生成一个.obj文件,此时已经成为机器语言的.obj文件,将会在链接时将会链接到一起生成可执行文件。
###例子
a.h

#ifndef A_H //防止多重包含
#define A_H
class C_A 
{
pulic:
	void funA();
};
#endif//A_H

a.cpp

#include<iostream>
#include"a.h"
#include "global.h"

void C_A::funA()
{
  i=0;
  std::cout <<i <<std::endl;
}

b.h文件

#ifndef B_H
#define B_H
class C_B
{
public:
	void funB();
};
#endif // B_H

b.cpp文件

#include<iostream>
#include"global.h"
#include"b.h"
void C_B::funB()
{
 i=1;
 std::cout << i << std::endl;
}

global.h文件

#ifndef GLOBAL_H
#define GLOBAL_H
extern int i;
#endif //GLOBAL_H

global.cpp文件

int i ;//申请内存

main.cpp文件

#include"a.h"
#include"b.h"

void main()
{
C_A a;
C_B b;
a.funA();
b.funB();
}

程序很简单,但是如果我要注释掉extern int i;IDE会报什么样的错误呢?
我们推断一下,首先在预处理阶段不会报错,三个cpp文件会将他们包含的头文件的代码部分在分别的.cpp文件展开,成为新的文本文件。
在编译阶段也不会出错,因为没有语法错误,新的源文件会被编译成汇编语言,此时还是一个文本文件,此时应该还定义了程序中的变量应该申请多少内存,在程序运行时向系统索要内存。
在汇编阶段将会转化为a.obj、b.obj、gobal.obj,main.obj,此时为二进制,为机器语言。
链接阶段,应该为将四个文件链接到一起,a.obj中包括一个整形的i被定义,b.obj中也有一个i被定义,global.obj也有一个i被定义,链接到一起时检测到多个相同名称的变量存在,出错!报错为找到一个或多个多重符号的定义。所以要在global.h文件中声明i,这样连接器检测到i为一个声明,在不同的obj文件中进行赋值。通过编译。
那在global.h文件中声明一个函数,在.cpp文件实现,编译器会不会说函数多重定义呢?答案是不会,因为函数声明和定义的方式不一样,而变量的声明和定义如果不加extern关键字则会一样,无法辨别变量是声明还是定义,所以要有extern的存在。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值