头文件如何知道函数原型的实现在哪里?
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.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
所以这意味着我指示要编译的文件的顺序无关紧要?
有两个不同的阶段,编译和 linking。
- 在编译过程中,编译器只需要知道函数的原型。
- 在 linking 期间,目标文件实际上是 link 一起编辑的。
因此,在编译期间,where 部分不是必需的。但是,在 linking 时,该函数应该存在于一起 linked 的目标文件之一中。
详细说明,这就是我们看到的原因,即使缺少头文件(函数的前向声明)但具有所有必需的目标文件,编译和 linking 仍可能发生(带有警告,显然)(并且 linker 实际上可以找到并 link 所需的函数实现),但即使使用正确的头文件,如果您不提供包含实际定义的所需目标文件, link 人会 冲你尖叫 抛出错误。
编译器不知道。链接器会。
每个源文件都编译成目标文件:
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 链接到可执行文件时,它会执行必要的重定位。
我有以下文件:
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
所以这意味着我指示要编译的文件的顺序无关紧要?
有两个不同的阶段,编译和 linking。
- 在编译过程中,编译器只需要知道函数的原型。
- 在 linking 期间,目标文件实际上是 link 一起编辑的。
因此,在编译期间,where 部分不是必需的。但是,在 linking 时,该函数应该存在于一起 linked 的目标文件之一中。
详细说明,这就是我们看到的原因,即使缺少头文件(函数的前向声明)但具有所有必需的目标文件,编译和 linking 仍可能发生(带有警告,显然)(并且 linker 实际上可以找到并 link 所需的函数实现),但即使使用正确的头文件,如果您不提供包含实际定义的所需目标文件, link 人会 冲你尖叫 抛出错误。
编译器不知道。链接器会。
每个源文件都编译成目标文件:
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 链接到可执行文件时,它会执行必要的重定位。