C++程序编译之谜——多文件编译的奇怪现象

左手编程,右手年华。大家好,我是一点,关注我,带你走入编程的世界。

公众号:一点sir,关注领取编程资料

1、奇怪的现象

在C++多文件编译的时候,很多人都会经常碰见这样的一种情况,在一个cpp文件中调用另一个cpp文件的函数,那么可以直接调用吗?我们来做个试验。

有以下三个文件main.cpp,cal.h,cal.cpp main.cpp

c 复制代码
#include <stdio.h>
#include "cal.h"
int main(int argc, char *argv[])
{
    printf("add(5,4) is %d\n", add(5, 4));
    return 0;
}

cal.h

c 复制代码
//cal.h
#include <stdio.h>
int add(int x, int y);

cal.cpp

c 复制代码
//cal.cpp
#include "cal.h"
int add(int x, int y)
{
    return x + y;
}

那么请问,我如果直接在main.cpp文件中直接调用cal.cpp中的函数方法可以吗?或者我换种方式问,请问可以编译通过吗?可以运行通过输出结果吗?

我在网上搜寻答案的时候,发现有些人表示可以很顺利的运行通过,而有些人表示完全按照提示的方法,复制黏贴,却报了找不到函数方法的错误:

csharp 复制代码
undefined reference to `add(int, int)'

那么请问到底是怎么回事呢?千万不要觉得说肯定是他们漏复制了什么,漏了函数声明什么的,这些都不是原因。那么是什么原因呢?

2、真正的原因

真正的原因是IDE在搞鬼!

首先我们要明白一下,像C/C++、java等高级语言编译生成可执行文件是要经历预处理、编译、汇编、链接这几个过程,像以上三个文件,头文件仅仅只参与到预处理过程,将cal.h的内容包含到另外两个cpp文件中,而另外两个cpp文件是要经历编译、汇编生成机器语言的二进制文件,也就是说两个cpp都会各自生成各自的二进制文件。

但是这个还没完,要生成可执行文件,还要将以上cpp文件生成的二进制文件进行链接起来,并且有个文件中还要提供一个main函数入口,因为C++语言的可执行文件的入口是main函数,不提供的话程序无法运行。

如果在Linux平台上要清楚的展现,就是以下这几个语句:

less 复制代码
gcc -c main.cpp  //会生成main.o文件
gcc -c add.cpp   //会生成add.o文件
gcc main.o add.o -o main

生成的.o文件就是二进制文件,然后将二进制文件进行链接生成可执行文件,也可以用以下这个语句一步到位:

css 复制代码
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()这个函数的接口,而我不想把函数具体的实现也提供出来,像在网络上如果应用第三方库的时候,别人不希望把他们的源码提供出来,但是又想提供这个接口给调用者调用,那么这时候该怎么做呢?

方法是有,下回分解。

相关推荐
无厘头三四十3 天前
现代编译器直接生成机器码的原理
编译原理
猪哥帅过吴彦祖6 天前
从源码到可执行文件:揭秘程序编译与执行的底层魔法
操作系统·编译原理·编译器
poemyang12 天前
性能优化之母:为什么说“方法内联”是编译器优化中最关键的一步棋?
java虚拟机·编译原理·即时编译器·方法内联
poemyang15 天前
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析
java虚拟机·编译原理·逃逸分析·即时编译器
前端缘梦16 天前
解锁webpack核心技能(三):从源代码到打包产物编译过程的原理指南
webpack·编译原理·前端工程化
poemyang16 天前
解锁硬件潜能:Java向量化计算,性能飙升W倍!
java虚拟机·编译原理·jit·向量化计算·smid
poemyang17 天前
Java编译器优化秘籍:字节码背后的IR魔法与常见技巧
java虚拟机·编译原理·ir·即时编译器
poemyang18 天前
“代码跑着跑着,就变快了?”——揭秘Java性能幕后引擎:即时编译器
java·java虚拟机·编译原理·jit·即时编译器
poemyang19 天前
“同声传译”还是“全文翻译”?为何HotSpot虚拟机仍要保留解释器?
java·java虚拟机·aot·编译原理·解释执行
漂流瓶jz21 天前
JavaScript语法树简介:AST/CST/词法/语法分析/ESTree/生成工具
前端·javascript·编译原理