问题
由于之前项目做得很少,一直没有注意到这个问题,include一直认为就是直接把include的文件复制过来,并没有去深究里面的原理。但今天做项目时发现如果是直接复制过来,那include的文件里include的其他文件的地址岂不是就要填之前的源代码文件的相对地址了吗?(a引入b,b又要引入c)但这当然不符合常人的思想,毕竟这样工作的话如果另外一个文件也要用到这个头文件地址就乱了。
测试环境
- Windows 10
- Code::Blocks(编译器:MinGW-W64)
测试开始
首先建好一个main.c
的文件
#include <stdio.h>
int main()
{
return 0;
}
在main.c
文件目录下建一个include
文件夹,在include
文件夹中再建两个头文件fun1.h
和fun2.h
我们先试试如果是直接复制粘贴include的内容的情况,即include相对于源代码的地址
fun1.h
#include "include/fun2.h"
void fun1()
{
}
fun2.h
void fun2()
{
}
我们修改main.c
文件,引入fun1.h
#include "fun1.h"
int main()
{
return 0;
}
这样如果符合直接复制的这个猜想,得到的应该是这样的,似乎并没有什么问题。
#include "include/fun2.h"
void fun1()
{
}
int main()
{
return 0;
}
编译结果:没有找到include/fun2.h
fatal error: include/fun2.h: No such file or directory|
我们再修改一下fun1.h
,将fun2.h
的地址改为相当于fun1.h
的地址
#include "fun2.h"
void fun1()
{
}
编译运行 没有问题。
Process returned 0 (0x0) execution time : 0.016 s
Press any key to continue.
至此,我们已经可以确定,这种情况下我们include
的地址是要填写使用相对于include
的此文件的地址(即a引用b,b引用c时写c的地址要写相对于b而言的地址),这也是我们认知所更能接受的。我们去验证一下这个猜想是否正确。
验证
一个源文件在编译前还有一段预编译(预处理)阶段,这个阶段会把我们的include
全部去掉,变成include
的文件中的内容并全部内容整合到一个文件,我们找到我们的main.h
预编译后的文件,看看它到底是什么样的。
打开cmd命令行,调整到我们main.c
的目录,输入gcc -E main.c
(含义:预处理main.c
)我们得到的是
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
# 1 "include/fun1.h" 1
# 1 "include/fun2.h" 1
void fun2()
{
}
# 2 "include/fun1.h" 2
void fun1()
{
}
# 2 "main.c" 2
int main()
{
return 0;
}
我们可以发现,此时已经把#include "fun2.h"
替换为了"include/fun2.h"
,看来预处理是会把include
的地址处理成一个正确的地址的。
扩展
那include
的文件到底是只会把此文件include
其他文件的地址修改还是会把包括代码中的其他部分的地址全部修改呢
我们把fun1.h
添加点东西,现在fun1
的功能是创建一个名为kadia.txt
的文件
#include <stdlib.h>
#include "fun2.h"
void fun1()
{
system("type nul>kadia.txt");
}
在main.c
中调用fun1
#include "include/fun1.h"
int main()
{
fun1();
return 0;
}
编译运行后我们发现,在main.c
的目录下创建了一个kadia.txt
,而在include
目录中并没有,看来代码中的include外的地址并没有改变,而是直接复制了过来,这一点也在预编译的文件中得到了验证
# 1 "include/fun2.h"
void fun2()
{
}
# 3 "include/fun1.h" 2
void fun1()
{
system("type nul>kadia.txt");
}
总结
在多层的include
中,父层引入子层的include
文件时会在地址前加上子层的地址,即(a引入c时会在c的地址前加上b的地址),include
外的地址内容不会改变,直接复制到父层。