1、奇怪的现象
在C 多文件编译的时候,很多人都会经常碰见这样的一种情况,在一个cpp文件中调用另一个cpp文件的函数,那么可以直接调用吗?我们来做个试验。
有以下三个文件main.cpp,cal.h,cal.cpp
代码语言:javascript复制1 //main.cpp
2 #include <stdio.h>
3 #include "cal.h"
4 int main(int argc, char *argv[])
5 {
6 printf("add(5,4) is %dn", add(5, 4));
7 return 0;
8 }
代码语言:javascript复制1 //cal.h
2 #include <stdio.h>
3 int add(int x, int y);
代码语言:javascript复制1 //cal.cpp
2 #include "cal.h"
3 int add(int x, int y)
4 {
5 return x y;
6 }
那么请问,我如果直接在main.cpp文件中直接调用cal.cpp中的函数方法可以吗?或者我换种方式问,请问可以编译通过吗?可以运行通过输出结果吗?
我在网上搜寻答案的时候,发现有些人表示可以很顺利的运行通过,而有些人表示完全按照提示的方法,复制黏贴,却报了找不到函数方法的错误:
undefined reference to `add(int, int)'
那么请问到底是怎么回事呢?千万不要觉得说肯定是他们漏复制了什么,漏了函数声明什么的,这些都不是原因。那么是什么原因呢?
2、真正的原因
真正的原因是IDE在搞鬼!
首先我们要明白一下,像C/C 、java等高级语言编译生成可执行文件是要经历预处理、编译、汇编、链接这几个过程,像以上三个文件,头文件仅仅只参与到预处理过程,将cal.h的内容包含到另外两个cpp文件中,而另外两个cpp文件是要经历编译、汇编生成机器语言的二进制文件,也就是说两个cpp都会各自生成各自的二进制文件。
但是这个还没完,要生成可执行文件,还要将以上cpp文件生成的二进制文件进行链接起来,并且有个文件中还要提供一个main函数入口,因为C 语言的可执行文件的入口是main函数,不提供的话程序无法运行。
如果在Linux平台上要清楚的展现,就是以下这几个语句:
代码语言:javascript复制gcc -c main.cpp //会生成main.o文件
gcc -c add.cpp //会生成add.o文件
gcc main.o add.o -o main
生成的.o文件就是二进制文件,然后将二进制文件进行链接生成可执行文件,也可以用以下这个语句一步到位:
gcc add.cpp main.cpp -o main
这样子的话在运行可执行文件,就会输出正确结果,不会报错了。
那么我们再回到开头的那个问题,为什么有些人可以正确的输出不会报错,而有些人却会报错呢?首先我猜测他们都是在window平台执行的,并且是用IDE来编译的,而不同的IDE功能都各不相同,有些IDE非常的智能,它可能会根据在main文件中导入的h文件自动去寻找对应的cpp文件,比如像上面我在main.cpp文件中导入了add.h的头文件,那么IDE会自动去寻找看看是否有add.cpp文件,有的话进行编译、链接,输出结果。
当然,这些只是我的猜测,可能IDE也有其他办法可以找出文件间的关系,然后进行编译。不管如何,有些IDE中确实是可以实现这样子的功能,但有些比较简单的IDE就没有这么智能了,这时候可能就会报以上错误,这个可能就需要你进行某些设置,至于如何设置,这个不同IDE都不相同,大家可以自己去网上搜搜答案。
3、新的疑团
那么可能有些人这时候会提出一个疑问,如果我只想提供add()这个函数的接口,而我不想把函数具体的实现也提供出来,像在网络上如果应用第三方库的时候,别人不希望把他们的源码提供出来,但是又想提供这个接口给调用者调用,那么这时候该怎么做呢?
方法是有,下回分解。