您当前的位置:首页 > 计算机 > 编程开发 > C语言

C语言多文件编译、链接的原理

时间:01-03来源:作者:点击数:

在讲解 externstatic 关键字的时候,我们已经给出了几个简单的多文件编程的例子,现在不妨再看一个例子。

main.c 源码:

#include <stdio.h>
#include <conio.h>
// 也可以不写 extern;为了程序可读性,建议写上
extern long sum(int, int);
// 必须写 extern
extern char* OS;
int main()
{
    int n1 = 1, n2 = 100;
    printf("从%d加到%d的和为%ld [By %s]", n1, n2, sum(n1, n2), OS);
    getch();
    return 0;
}

module.c 源码:

#include <stdio.h>
// 当前操作系统
char *OS = "Windows 7";
long sum(int fromNum, int endNum){
    int i;
    long result = 0;
    // 参数不符合规则,返回 -1
    if(fromNum<0 || endNum<0 || endNum<fromNum){
        return -1;
    }
    for(i=fromNum; i<=endNum; i++){
        result += i;
    }
    // 返回大于等于0的值
    return result;
}

运行结果:从1加到100的和为5050 [By Windows 7]

这个程序,我们按照“编译 --> 链接 --> 运行”的步骤来生成,不要按 F5 或者 F7(对于 Visual C++)直接生成 exe。如果已经生成,可以清理掉相关文件。

注意:一个程序有且只能有一个 main() 函数,即使它有多个源文件。main() 函数是程序的入口函数,双击运行程序时就从这里开始执行。

编译和链接的原理

对于C,首先要把源文件编译(Compile)成目标文件(Object File),也就是Windows下的 .obj 文件。然后再把单个或多个 Object File 合并成可执行文件,也就是Windows下是 .exe 文件,这个动作叫作链接(Link)。

编译时,编译器需要检查语法是否正确,函数、变量的声明是否正确;只有函数、变量的声明但没有定义是完全正确的。函数声明是告诉编译器该函数已经存在,但是入口地址还未确定,暂时在此做个标记,链接时编译器会找到函数入口地址,并将标记替换掉。

这些都校验通过,编译器就可以编译出中间目标文件。一般来说,编译是针对单个源文件的,多个源文件需要编译多次,每个源文件都会生成一个对应的目标文件。

编译产生的 .obj 文件已经是二进制文件,与 .exe 的组织形式类似,只是有些函数的入口地址还未找到,程序不能执行。链接的作用就是找到函数入口地址,将所有的源文件组织成一个可以执行的二进制文件。

链接时,主要是链接函数和全局变量。链接器并不管函数或变量所在的源文件,只管中间目标文件(Object File)。

总结一下:源文件首先会生成中间目标文件,再由中间目标文件生成可执行文件。在编译时,编译器只检测程序语法、函数声明、变量声明是否正确。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是 Link 2001 错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File。

一步一步生成 exe 文件

知道了编译链接的原理,接下来我们使用VC一步步的生成 .exe 文件。

首先切换到 main.c 面板,按下 Ctrl+F7 键(编译),打开项目目录下的 Release 或 Debug 文件夹,可以看到多出了一个 main.obj 文件,这就是 main.c 生成的目标文件。

再切换到 module.c 面板,进行同样的操作,会生成 module.obj 文件,至此编译完毕(所有的源文件都编译过了)。

最后,按下 F7 键(链接),就生成了 main.exe,双击运行就可以看到上面的输出结果了。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门