> 文章列表 > 函数未定义是在哪个环节被发现的?

函数未定义是在哪个环节被发现的?

函数未定义是在哪个环节被发现的?

回答:在链接环节

有一个这样的程序

 程序声明一个fun函数,在并在主函数中调用。

当运行时,会产生错误

这里截取错误信息

 错误主要有:无法解析fun函数符号

本文就将对这种常见错误信息进行剖析,知其由来。

一、一个C程序如何运行

首先就必须大致的了解一个C程序是如何运行起来的。

程序的运行依赖于翻译环境和执行环境

1)翻译环境

一个程序可能由多个源文件组合,程序分别对每一份程序进行编译,生成.obj(目标文件),每个目标文件由链接器组合在一起,形成一份完整的可执行程序。

 2)运行环境

程序由操作系统程序载入内存,由main函数开始,创建函数栈帧,保存局部变量,最后销毁栈帧,结束程序。

二、编译过程

知道程序的运行了,那么就回头再看看编译过程

编译其实也分几个阶段:

1.预处理

2.编译

3.汇编

 下面对每个部分也进行简单概述

1.预处理( .c -> .i)

删除注释  //   /*  */

#define删除   所有宏替换

头文件展开  #include< >   #include" "

添加行号和文件标志

预处理之后,会生成.i文件    gcc环境下  -E开始查看预处理之后的.i文件

2.编译( .i  ->.s )

词法分析

语法分析

语义分析

符号汇总

这里就详细解释一下符号汇总

符号汇总是发生在编译过程,对每一个全局的变量和函数进行汇总

一个test.i文件,如果只包含fun函数的声明和main函数,以及一个全局变量,那么符号汇总,就是对这三者进行收集

 3.汇编(.s->.o)

生成符号表

汇编指令生成二进制指令.obj文件

生成符号表:

 在C文件中,符号表的组成包含_函数名,以及函数地址

在test.s文件中,由于fun只是一个声明,无法得到其的地址,所以就用一个无效指针(NULL)暂时表示

到这里编译过程就完成

三、链接

合并段表

符号表的合并

符号表的重定位

符号表的合并与重定位

有多少个文件,经过编译后就会生成多少个符号表,链接时,就会将这些符号表合并成一个。

重定位:对于符号表中的无效地址,会进行寻找,替换成正确地址。

 

到这里,就能回答开头的问题:

如果函数没有定义,那么在符号表的合并和重定位时,就无法找到正确的地址,那么就会链接错误。

留个思考

如果函数只是名称不同,而内容相同,会发生链接错误吗?

.o文件通过链接后生成.exe文件,依赖于便于环境,完成程序。

四、总结

函数未定义的发现是出现在符号表的合并和重定位。

通过本文,了解一个程序如何执行,了解编译的简单过程。

符号表在C++中的作用更明显,涉及到函数的重载。

本文就提到这,感谢阅读!