关于头文件是否参与编译的讨论

一、文章来由

写项目的时候发现了这个问题,又是一个比较底层的问题,首先说明,这篇文章只是我根据查阅的资料和做的实验提出的一个讨论,并不一定就是正确答案。因为这个问题网上众说纷纭,我很欢迎大家参与这个讨论,一起搞懂这个问题~~~

二、问题的提出

问题就是。。。

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函数写在头文件,也可以正常执行。

版权声明:欢迎转载,注明出处就好!如果不喜欢请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步!!

时间: 2024-08-28 10:24:57

关于头文件是否参与编译的讨论的相关文章

C++头文件中预编译宏的目的

C++头文件中预编译宏的目的 eg: #ifndef _FACTORY_H_#define _FACTORY_H_......#endif //~_FACTORY_H_ 防止头文件被重复包含,导致变量或类型被重复定义 C++头文件中预编译宏的目的

VS2008 工程中部分文件不参与编译 从生成中排除【Worldsing笔记】

Visual Studio 2008 .VS2008.VC2008工程源文件配置.编译配置 ? 有时编写代码时,往往存在这样的需求(或是希望有这样的功能):一个工程经过不共同的配置实现不同的版本或是功能,比如做开发包的Dome,一个库文件, 有多个API接口,以lib文件给用户提供时,我们需要提供文档和Demo,你可以一个Demo建立一个工程,但是,像VS2008这样的高级开发工具应该有解决 办法的,关键是你不知道怎么用,在VS2008环境下有这样几种解决办法: ? 建立一个工作区,在工作区里建

C预编译, 预处理, C/C++头文件, 编译控制,

在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征.依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的. 其格式一般为: #Pragma Para 其中Para 为参数,下面来看一些常用的参数. (1)message 参数. Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输

linux-gcc 编译时头文件和库文件搜索路径

一.头文件  gcc 在编译时寻找所需要的头文件 :  ※搜寻会从-I开始  ※然后找gcc的环境变量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH  ※再找内定目录/usr/include /usr/local/include/usr/lib/gcc-lib/i386-linux/2.95.2/include/usr/lib/gcc-lib/i386-linux/2.95.2/include/g++-3/usr/lib/gcc-lib/

C++预编译头文件

以前只是学过C++中的预编译头文件,但一直没用过:既然今天又遇到了这个问题,所以还是决定写点总结 算是做个笔记吧! 在C++中之所以出现预编译的概念主要是因为在C++项目中导致整个程序的编译过程变得很缓慢的一个很重 要的原因就是C++头文件的存在,在每一个.cpp文件中都会包含许多.h的头文件,如果所包含的头文件过多或过大 就会导致.cpp文件过大而编译缓慢,但是事实上在许多.cpp中所包含的头文件都是重复出现的,即有很多头文件被 重复编译了许多次,这当然会导致项目整体的编译速度变慢. 为了解决

C++预编译头文件(#include &quot;stdafx.h&quot;)

来源:http://blog.sina.com.cn/s/blog_4ac766c00100qsbd.html http://blog.csdn.net/txh0001/article/details/7031058 作为一个C++菜鸟,在预编译头文件(#include "stdafx.h")上纠结了很久,今天打算彻底弄明白它. 1.预编译头文件的概念 所谓的预编译头文件,其实我们很熟悉的,这里的头文件(Microsoft Visual C++中)一般的说就是我们常见的stdafx.h

27&gt;&gt;gcc编译时头文件和库文件搜索路径

一.头文件 gcc 在编译时寻找所需要的头文件 : ※搜寻会从-I开始(gcc 参数,指定头文件搜索位置) ※然后找gcc的环境变量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH ※再找内定目录 /usr/include /usr/local/include /usr/lib/gcc-lib/i386-linux/2.95.2/include /usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i

整理Linux下gcc编译中关于头文件与库文件搜索路径相关问题

分类: MakeFile/Make/GCC/LD2010-11-20 23:15 535人阅读 评论(0) 收藏 举报 转者的话: 本文详细介绍了gcc 编译时 搜索头文件的路径以及方式, 编译时寻找lib库的方式, 以及运行时加载库的寻找方式!!!非常之经典啊!以后有新的知识都汇总到这里来了! 在交叉编译的时候我们需要用到其他的库,在config时候可以通过“-I”来指定头文件目录,但是每次都需要设置的话难免有些麻烦,找到一个简单的方法. 看下文的红色部分. 有大量的环境变量可供设置以影响 G

C++中的头文件和源文件

一.C++编译模式通常,在一个C++程序中,只包含两类文件——.cpp文件和.h文件.其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码:而.h文件则被称作C++头文件,里面放的也是C++的源代码.C+ +语言支持“分别编译”(separate compilation).也就是说,一个程序所有的内容,可以分成不同的部分分别放在不同的.cpp文件里..cpp文件里的东西都是相对独立的,在编 译(compile)时不需要与其他文件互通,只需要在编译成目标文件后再与其他的目标文件做一次链