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

一、文章来由

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

二、问题的提出

问题就是。。。

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 在开头,就可以正常使用函数。这又是一个预处理的典型代表,说明了在函数里面定义了函数~~~

其实甚至可以写出这种鬼畜的代码:

// testheadcompile.h
1, 2, 3, 4

//main.cpp
#include <iostream>
using namespace std;

int main()
{
    int a[] = {
        #include "testheadcompile.h"
        ,5
    };

    cout<<a[4]<<endl;
    return 0;
}

答案是5

2.3 问题3:

既然上面说是预编译,或者说是单纯的复制,那么那些没有实现的函数预编译?编译?链接的时候编译器怎么做的?那些实现了,在整个过程没有用到的函数呢???

这个问题,我是这样看的:

所有的编译都是单独的,没有实现的函数,就没有单独实现的编译,如果用到了,找不到实现体,就会报链接错误,也就是vs里面常见的“fatal error LNKXXX: N 个无法解析的外部命令”。。。

而对于头文件的作用仅仅是为了在编译的时候告诉编译器,这里如果用到一些其他文件的东西,我实现了,编译别报错!

所以这么说,实现了,但在整个过程没有用到的函数,是编译了的,但没有被链接进最后的可执行文件。(可能有不对的地方,欢迎指正)

2.4 问题4:

既然说没有参与编译,只是参与预编译,但是可以在头文件里面定义函数,又如何解释?

首先我来回答一下这个问题,个人感觉是参与编译的,但是是头文件被包含到源文件进行编译,也就是说编译器只会编译源文件,不被包含的头文件是没有存在的意义的,因为我故意把头文件写错,然后这样报错。。。

刚刚测试发现了一个现象,没有cpp文件,vs也可以编译,我怀疑在编译的时候,默认将main函数所在的文件作为编译文件,即使main函数写在头文件,也可以正常执行。

而在Linux下面,用编译器编译时需要指定编译的文件,所以有没有后缀名是无关紧要的,反正都是文本文件,读取方式就是确定的,所以Linux对于后缀名并不重要。

时间: 2024-08-27 03:42:17

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

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

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

C++头文件编译问题

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

通过预编译头文件来提高CB的编译速度

C++ Builder是最快的C++编译器之一,从编译速度来说也可以说是最快的win32C++编译器了.除了速度之外,C++builder的性能也在其它C++编译器的之上,但许多delphi程序员仍受不了C++builder工程的编译速度.的确,delphi的速度要比任和c++的编译器都要快好多.Delphi在编译一个小工程的时候可能不到一秒,大的工程一般也在5秒钟这内编译完成了. 为什么delphi会比c++builder快这么多?是否有方法来c++builder的编译速度?本文就讲解了为什么

C++预编译头文件

许多初学 VC 的朋友也许都为那么一个问题困扰过:     为什么所有的 cpp 都必须 #include "stdafx.h"     也许请教了别的高手之后,他们会告诉你,这是预编译头,必须包含.可是,这到底是为什么呢?预编译头有什么用呢?     这得从头文件的编译原理讲起.其实头文件并不神秘,它的全部作用,就是把自己的所有内容直接"粘贴"到相应的 #include 语句处.如果不相信的话,不妨做个实验,将一个 cpp 中的所有 #include 语句删掉,并

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/../../../..

解析VC中预编译头文件的深入分析_C 语言

一.为什么预编译头文件:预编译头的概念: 所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以.pch为扩展名的),这个文件就称为预编译头文件这些预先编译好的代码可以是任何的C/C++代码,甚至是inline的函数,但是必须是稳定的,在工程开发的过程中不会被经常改变.如果这些代码被修改,则需要重新编译生成预编译头文件.注意生成预编译头文件是很耗时间的.同时你得注意预编译头文件通常很大,通常有6-7M大.注意及时清理那些没有用的预编译头文件.也许你会问:现在的编译器都有

C++中头文件和源文件详细介绍

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

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

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

c++-对C++头文件改变如增加一个变量或者随便打sdflksdjf对整个项目都没反应是怎么回事儿

问题描述 对C++头文件改变如增加一个变量或者随便打sdflksdjf对整个项目都没反应是怎么回事儿 对C++头文件改变如增加一个变量或者随便打sdflksdjf对整个项目都没反应是怎么回事儿 解决方案 你是怎么随便打的, 一般头文件里都是声明的, 也可以定义函数(定义的话就直接是内联函数了),如果随便打的话估计都让你编译不过去吧 解决方案二: 项目中没有任何一个cpp文件#include这个头文件,所以随便打什么都不会有反应. 解决方案三: 我就随便打了:sdkfjlskdjfl(在任何地方)