头文件如何知道函数原型的实现位置?

时间:2016-04-21 16:30:55

标签: c compilation linker header-files

我有以下文件:

的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.h my_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

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

2 个答案:

答案 0 :(得分:5)

编译器不知道。链接器确实。

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

main.c成为main.o,my_math.c成为my_math.o - 例如。

编译main.c my_math.h中的函数原型时,告诉编译器它会调用一个函数int add(int a, int b);,但它没有关于这个函数的额外知识。

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

答案 1 :(得分:4)

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

  • 在编译期间,编译器只需要知道函数的 prototype
  • 在链接期间,目标文件实际上是链接在一起的。

因此,在编译期间,不需要 where 部分。但是,在链接时,该函数应存在于一个链接在一起的目标文件中。

详细说明,这就是为什么我们看到,即使缺少头文件(函数的前向声明)但是包含所有必需的目标文件,编译和链接也会发生(显然有警告)(并且链接器实际上可以查找并链接所需的函数实现),但即使使用正确的头文件,如果您不提供包含实际定义的必需目标文件,链接器将向您尖叫 throw错误。