编译原理
#编译原理
今天组长教育了一下整个程序的编译过程,感觉自己对于这块了解还是很少,有许多知识之前知道,现在忘记了,还有很多规则只是知道,但并不知道它为什么要这样写,所以再次记录一下,有什么问题或者错误希望大家在评论区提出。。。。
编译原理
如图
预编译阶段
在预编译阶段,发挥作用的是预处理器(CPP)。预处理器读取.cpp文件,对其中的伪指令(#开头的指令)和特殊符号进行处理,特别的,对#include指令进行递归处理,包含需要的头文件。
常见的伪指令有#define、#include""(包括你需要的头文件),在你的预处理器处理过后,会将你#include的头文件中的代码内容(不包括预处理的内容)替换到你的.cpp文件中,也会将你#define的内容替换,会选择你条件编译(#if #else #endif)的代码块等汇总成一个新的源文件。
预处理阶段还会将注释删除
添加行号和文件名标识,方便调试使用
此时源程序还是文本文件。
###编译阶段
在这个阶段中,编译器(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的存在。
文章最后发布于: 2018-03-15 20:42:31
相关阅读
条件编译https://baike.baidu.com/item/条件编译/7692959#ifndefhttps://baike.baidu.com/item/%23ifndef/2835043?fr=aladdin
为什么TCP要进行三次握手 在谢希仁着“计算机网络”第四版中讲“三次握手”的目的是“ 为了防止已失效的连接请求报文段突然又传
Java程序运行原理分析 Java程序运行流程 Java程序运行原理分析----环境介绍 从最初的jdk安装开始,都是程序运行的关键步骤,每
如何提升创意,又如何才能获得源源不断的创意?笔者针对这个问题,总结了大脑的三个功能引发创新的原理,enjoy~广告人:这个广告创意,我为什
作为网站管理员,无论是个人站,还是企业站,甚至是门户站,最担心的无非就是不被搜索引擎所收录,在引擎里面得不到关键词相应的排名;然后,