连接
概述
一个 C 该程序可能由多个单独编译的部分组成,这些部分通过一个通常称为连接器的程序合并成一个整体。
什么是连接器?
C 语言中的一个重要思想是单独编译,即多个源程序可以在不同的时间单独编译,然后在适当的时间集成在一起。但连接器通常是与之相匹配的 C 编译器分离的,它不可能了解 C 语言的许多细节。尽管连接器不理解 C 然而,语言可以理解机器语言和内存布局。编译器的责任是把 C 源程序 翻译 成对连接器有意义的形式,使连接器能够 读懂 C 源程序了。
典型的连接器将由编译器或汇编器生成的几个目标模块整合成一个被称为载入模块或可执行文件的实体,可以由操作系统直接执行。其中,目标模块直接作为输入提供给连接器;其他目标模块包括类似的连接过程 printf 在函数库文件中获得。
当连接器输入时,有一组目标模块和库文件,当连接器输出时,有一个载入模块。连接器读取目标模块和库文件,并生成载入模块。对于每个目标模块中的每个外部对象,甚至机器也应检查载入模块,看看是否有相同名称的外部对象。如果没有,连接器将外部对象添加到载入模块中;如果有,连接器将开始处理命名冲突。
声明与定义
这是定义
int a; 这是声明
extern int a; 定义每个外部变量一次
命名冲突与 static 修饰符
两个名称相同的外部对象实际上代表了同一个对象,即使编程师的初衷不是这样,系统也会这样处理,static 修饰符是减少这种命名冲突的有用工具。
static 修饰符不仅适用于变量,也适用于函数。
检查外部类型
假定有一个 C 该程序由两个源文件组成。一个文件包含外部变量 a 的声明
extern int n; 另一个文件中包含外部变量 n 的定义
long n; 假设两个句子都不在任何函数中,所以 c 是外部变量。 这是无效的 C 程序,因为相同的外部变量在两个不同的文件中被声明为不同的类型,所以在每个目标模块中确保一个特定名称的所有外部定义都有相同的类型,这通常是程序猿的责任,相同的类型 严格意义上应该是一样的。例如,以下程序
定义包含在一件中:
char filename[] = "hello tyustli"; 声明包含在另一份文件中:
extern char *filename; 在第一个文件中 filename 在第二个文件中,它是字符数组的名称,而不是字符指针 filename 这两个对是指针 filename 声明使用存储空间的方式不同,不能以合理的方式共存。 纠正上例改法如下:
char filename[] = "hello world"; /* 文件1 */ extern char filename[]; /* 文件2 */ 或者:
char *filename = "hello world"; /* 文件1 */ extern char *filename; /* 文件2 */ 关于外部类型,C 语言规则是,如果一个未声明的标志符后面有一个开括号,则将被视为返回整形手术的函数。
头文件
在 file.h 中包含声明
extern char filename[]; 外部变量需要使用 filename 的每个 C 应在源文件中加入这样一句话:
#include "file.h" 最后是源文件 file.c 中,给出 filenae 的初始值
#include "file.h"
char filename[] = "hello world";
特别需要指出的是,定义该外部对象的模块也应该包含这个头文件。