头文件如何知道函数原型的实现在哪里?

How a header file knows where the implementation of a function prototype is?

我有以下文件:

main.c

#include <stdio.h>
#include "my_math.h"

int main()
{
    int a = 10, b = 5;
    add(a, b);
    return 0;
}

my_math.h

int add(int a, int b);

my_math.c

#include "my_math.h"
int add(int a, int b)
{
    return a + b;
}

我知道使用 #include "my_math.h" 将 my_math.h 文件的内容复制到调用它的文件中。但是,main.c 文件是如何实现 add() 函数的呢? 一开始我认为 my_math.hmy_math.c 应该匹配名称,但不匹配扩展名,但我有将名称从 my_math.c 更改为 my_matho.c 一切都像以前一样工作,所以 C 到底怎么知道函数的实现在哪里?

我正在使用以下命令编译:

gcc -g -O0 -Wall main.c my_math.c -o main

还有一个问题是它与之前的命令相同:

gcc -g -O0 -Wall my_math.c main.c -o main

所以这意味着我指示要编译的文件的顺序无关紧要?

有两个不同的阶段,编译和 linking。

  • 在编译过程中,编译器只需要知道函数的原型
  • 在 linking 期间,目标文件实际上是 link 一起编辑的。

因此,在编译期间,where 部分不是必需的。但是,在 linking 时,该函数应该存在于一起 linked 的目标文件之一中。

详细说明,这就是我们看到的原因,即使缺少头文件(函数的前向声明)但具有所有必需的目标文件,编译和 linking 仍可能发生(带有警告,显然)(并且 linker 实际上可以找到并 link 所需的函数实现),但即使使用正确的头文件,如果您不提供包含实际定义的所需目标文件, link 人会 冲你尖叫 抛出错误。

编译器不知道。链接器会。

每个源文件都编译成目标文件:

main.c 变为 main.o 并且 my_math.c 变为 my_math.o - 例如。

在编译main.cmy_math.h中的函数原型告诉编译器将有一个函数int add(int a, int b);可以调用,但它对这个函数没有额外的了解。

当链接器将 main.o 和 my_math.o 链接到可执行文件时,它会执行必要的重定位。