编译单元
当一个c或cpp档案在编译时,预处理器首先递归包含头档案,形成一个含有所有必要信息的单个源档案,这个源档案就是一个编译单元。
基本介绍
- 中文名:编译单元
- 外文名:translate unit
- 适用领域:程式、代码
- 相关概念:源档案、预编译、编译器
C++中的编译单元
编译单元,指的是代码的物理组织形式。根据C++标準,每一个cpp 档案就是一个编译单元。
- 编译器不会去编译 `.h` 或者 `.hpp` 档案;
- 编译器只会编译 `.c` 或 `.cpp` 档案;
简单来说,当一个c或cpp档案在编译时,预处理器首先递归包含头档案,这也就是为什幺常会有:#ifndef……#define……#endif。之后,形成一个含有所有必要信息的单个源档案,这个源档案就是一个编译单元。这个编译单元会被编译成为一个与cpp档案名称同名的目标档案 。
编译器不能检查跨越目标档案或编译单元之间的名称冲突,这是连结器的工作。连结器把不同编译单元中产生的符号联繫起来,构成一个可执行程式。如:
//档案first.cpp int integerValue = 0; int main(){ int integerValue = 0; return 0; }; //档案second.cpp int integerValue = 0; /* 错误: error LNK2005: "int integerValue" (?integerValue@@3HA) 已经在 second.obj 中定义 first.obj */
GCC将C++代码转为机器码,理论上需要四个步骤:预处理(preprocessing)、编译(compilation)、彙编(assembly)以及连结(linking)3;四个步骤对应四个主体:预处理器(preprocessor)、编译器(compiler)、彙编器(assembler)以及连结器(linker)。实际预处理与编译其实是一个步骤,共需要三个步骤:预处理&编译、彙编以及连结。
Java中的编译单元
当编写一个Java原始码档案时,此档案以.java结尾,被称为编译单元。
1、 编译单元中可以有一个public类,且只能有一个public类,作为外界访问该类的接口,该类的名称必须与档案名称称一样。
2、 编译单元中可以没有public类,但必须有一个类名称与档案名称称相同。
3、 编译单元中可以有一些额外的类,这些类在包访问许可权的。
代码组织
1、当编译(javac)一个.java档案时,在该编译单元(即.java档案)中的每个类都会有一个输出档案.class档案,每个输出档案的名称与.java档案中每个类的名称相同。
2、Java可运行程式是一组可以打包并压缩为一个Java文档档案(JAR档案)的.class档案。Java解释器负责这些档案的查找、装载和解释。
Java解释器运行过程
1、 找出环境变数CLASSPATH(通过作业系统设定,也可不用设定,一般编译环境会为你设定),CLASSPATH包含一个或多个目录,用来查找.class档案的根目录。
2、 从根目录开始,解释器获取包的名称并将每个句点替换成\
3、 得到的路径与CLASSPATH中的各个不同的项相连线,解释器就在这些目录中查找与你创建的类名称相关的.class档案。
在多个编译单元中如何定义常量(C++)
【方法一】: 在某个公用的头档案中直接在某个名字空间中或者全局名字空间中定义符号常量并初始化(有无static)无所谓,例如:
// CommonDef.h
const int MAX_LENGTH=1024;
然后每一个使用它的编译单元#include改头档案即可
const int MAX_LENGTH=1024;
然后每一个使用它的编译单元#include改头档案即可
【方法二】: 在某个公用头档案中并且在某个名字空间中或者全局名字空间中将符号常量声明为extern的,例如:
//CommonDef.h
extern const int MAX_LENGTH;
并且在某个源档案中定义一次并初始化:
const int MAX_LENGTH=1024;
然后每一个使用它的编译单元#include上述头档案即可。
//CommonDef.h
extern const int MAX_LENGTH;
并且在某个源档案中定义一次并初始化:
const int MAX_LENGTH=1024;
然后每一个使用它的编译单元#include上述头档案即可。
两种方法的比较
优点:
方法一:
维护方便
方法二:
(1)节约存储,每一个编译单元访问都是这个唯一的定义。
(2)修改初值后只需重新编译定义所在编译单元即可,影响面很小。
(2)修改初值后只需重新编译定义所在编译单元即可,影响面很小。
缺点:
方法一:
(1)如果修改常量初值,则将影响多个编译单元,所有受影响的编译单元必须重新编译。
(2)每一个符号常量在每一个包含了它们的编译单元内都存在一份独立的拷贝内容,每个编译单元访问的就是各自的拷贝内容,因此浪费存储空间。
方法二:
如果要改变初值,要改变源档案。