回答:在链接环节
有一个这样的程序
程序声明一个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++中的作用更明显,涉及到函数的重载。
本文就提到这,感谢阅读!