一、文章来由

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

二、问题的提出

问题就是。。。

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对于后缀名并不重要。

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

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

    C++头文件中预编译宏的目的 eg: #ifndef _FACTORY_H_ #define _FACTORY_H_ ...... #endif //~_FACTORY_H_ 防止头文件被重复包含,导 ...

  2. C++ : 编译单元、声明和定义、头文件作用、防止头文件在同一个编译单元重复引用、static和不具名空间...

    转 自:http://www.cnblogs.com/rocketfan/archive/2009/10/02/1577361.html 1. 编译单元:一个.cc或.cpp文件作为一个编译单元,生成 ...

  3. glibc的头文件 linux_求助,编译glibc头文件时出错

    我用的软件包如下: binutils-2.16.tar.gz gcc-3.4.4.tar.bz2 glibc-2.3.5.tar.gz glibc-linuxthreads-2.3.5.tar.gz ...

  4. 学习OpenCV时 ,添加:#includeopencv2/core/core.hpp等头文件出现无法编译的错误

     在使用win7+vs2010+opencv2.4.8时   经常在刚创建完项目--->源文件之后  ,添加头文件:#include<opencv2/core/core.hpp> ...

  5. C++控制台没有引用的头文件也会编译的原因

    导致原因:虽然主源文件没有引用相关的文件,而项目有包括这些文件到项目中.故而也会编译. 转载于:https://www.cnblogs.com/songtzu/archive/2013/01/12/2 ...

  6. Android9.0 HIDL头文件加log编译

    1.编译android.hardware.audio.core@all-versions-impl # 编译之前必须删除,不然不会生成新的android.hardware.audio.core@all ...

  7. CCS编译出错:缺少头文件的解决办法

    问题: "../Source/DSP2833x_SysCtrl.c", line 16: fatal error #5: could not open source file &q ...

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

    如何指定GCC的默认头文件路径 网上偶搜得之,以之为宝:) 原地址:http://blog.chinaunix.net/u/28781/showart.php?id=401631 ========== ...

  9. 【Android 高性能音频】Oboe 开发流程 ( 导入 Oboe 库 | 使用预构建的二进制库和头文件 | 编译 Oboe 源码 )

    文章目录 一.导入 Oboe 库 二.使用预构建的二进制库和头文件 三.编译 Oboe 源代码 Oboe GitHub 主页 : GitHub/Oboe ① 简单使用 : Getting Starte ...

最新文章

  1. puppet(1.7-2.1)
  2. golang float string int 相互转换 保留小数位
  3. spring boot 表单的实体提交错误:Validation failed for object='book'. Error count: 2
  4. Visual Studio 2017 - Update 2预览版已发布
  5. spring bean的创建,生命周期
  6. printstream_Java PrintStream close()方法与示例
  7. 关于mysql优化_关于MySQL优化的几点总结
  8. django-用户文件的上传-后台上传
  9. Idea日常使用记录
  10. JSP中contentType和pageEncoding的区别
  11. linux如何查看jupyter日志_在Linux服务器上运行Jupyter notebook server教程
  12. Toolbar的简单使用和封装
  13. v4l2API无法执行VIDIOC_DQBUF的问题
  14. 2013元旦成都九寨沟攻略
  15. C 语言实例 - 判断奇数/偶数
  16. abaqus算出来的转角单位是什么_ABAQUS中的单位使用方法
  17. 怎么使用openssl来生成一个自签名的x509证书?
  18. 最简单易懂的10堂算法入门课——算法是什么
  19. 二叉搜索树插入算法C#演示的代码
  20. 数独题 HDU - 1426

热门文章

  1. sox处理mp3_音频处理常用Linux命令总结(一)
  2. java 迭代器的原理_java里Iterator的原理
  3. dvwa安装包linux,dvwa安裝、配置、使用教程(Linux)
  4. 图像语义分割_图像语义分割(9)-DeepLabV3: 再次思考用于图像语义分割的空洞卷积...
  5. android从服务检查,android开发分享Android:你如何检查是否启用了特定的AccessibilityService...
  6. linux可用的ftp,linuxunix下有很多可用的ftp服务器
  7. php判断url参数为空,PHP检查url链接是否已经有参数的简单示例
  8. oracle数据库配置管理,Oracle配置管理
  9. nodejs+php+aes加密解密,php,crypto_php与nodejs的加密数据互通,php,crypto,node.js - phpStudy...
  10. 1445.32php,nginx实现mysql的负载均衡