一、文章来由
写项目的时候发现了这个问题,又是一个比较底层的问题,首先说明,这篇文章只是我根据查阅的资料和做的实验提出的一个讨论,并不一定就是正确答案。因为这个问题网上众说纷纭,我很欢迎大家参与这个讨论,一起搞懂这个问题~~~
二、问题的提出
问题就是。。。
2.1 问题1(主问题):
头文件是否真正参与编译?
先上一个网上的标准答案:
.h的内容被插入到.c中,作为.c的内容被编译。.h文件本身不直接参加编译。
据我理解,这句话就是说明了头文件不直接参与编译,是作为一个插入来理解。
也就是说:
是要编译的,只不过这些头文件是预编译的。每个源文件包涵的头文件都会被预编译包含到源文件中去。
这样就又牵出来三个子问题~~
2.2 问题2:
预编译是什么?
网上的答案大致理解为类似复制粘贴的操作,这样理解是有理由的,因为
(1)头文件不一定是 .h 文件,可以是任意类型
(2)头文件可以定义一些很奇怪的东西,见下面的代码
// testheadcompile.h
1, 2, 3, 4, 5
//main.cpp
#include <iostream>
using namespace std;
int main()
{
int a[] = {
#include "testheadcompile.h"
};
cout<<a[1]<<endl;
return 0;
}
分析:
这段代码可以说是真的变态,因为头文件写在了函数体内,这么说的确就像是一个复制粘贴,关键是可以跑出结果,我在vs2012 release模式下,结果如下:
而且还被360误认为是木马。。。
于是我这样认为:如果需要什么东西(变量或者方法)的时候,就直接可以像利用 #define 一样用 #include 了?而且#include,有井号本身就是宏的写法~~
但是发现,把 include 像上面一样写在方法体内,定义变量可以,函数不行,否则会报“本地函数定义是非法的”的错,但如果 include 在开头,就可以正常使用函数。这又是一个预处理的典型代表,说明了在函数里面定义了函数~~~
2.3 问题3:
既然上面说是预编译,或者说是单纯的复制,那么那些没有实现的函数预编译?编译?链接的时候编译器怎么做的?那些实现了,在整个过程没有用到的函数呢???
这个问题,我是这样看的:
所有的编译都是单独的,没有实现的函数,就没有单独实现的编译,如果用到了,找不到实现体,就会报链接错误,也就是vs里面常见的“fatal error LNKXXX: N 个无法解析的外部命令”。。。
而对于头文件的作用仅仅是为了在编译的时候告诉编译器,这里如果用到一些其他文件的东西,我实现了,编译别报错!
所以这么说,实现了,但在整个过程没有用到的函数,是编译了的,但没有被链接进最后的可执行文件。(可能有不对的地方,欢迎指正)
2.4 问题4:
既然说没有参与编译,只是参与预编译,但是可以在头文件里面定义函数,又如何解释?
首先我来回答一下这个问题,个人感觉是参与编译的,但是是头文件被包含到源文件进行编译,也就是说编译器只会编译源文件,不被包含的头文件是没有存在的意义的,因为我故意把头文件写错,然后这样报错。。。
刚刚测试发现了一个现象,没有cpp文件,vs也可以编译,我怀疑在编译的时候,是有一个大的包含,即使main函数写在头文件,也可以正常执行。
版权声明:欢迎转载,注明出处就好!如果不喜欢请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步!!