谈谈头文件

2023-11-03

一、头文件的定义
C语言中常常使用预处理指令#include,把另一个文件的内容复制到源文件当中,被复制的文件就是头文件,其后缀名为.h。
二、头文件的作用
1、在多文件的工程当中,头文件用于全局变量、外部函数的声明,其本身不包含程序的实现代码
例如:
extern int var;//var在某个c文件中定义
extern void myFunction(void);//一般情况下,都默认该函数为外部函数,因此可以把extern省略掉

2、用typedef给现有的类型起个新名字
例如:
typedef int ElementType;
typedef struct LinkedList
{
    ElementType value;
    struct LinkedList *next;
}*LinkedList;

3、宏定义
例如:
#define TRUE 1
#define FALSE 0
三、头文件的书写方式
  如上所述,#include的本质是把头文件的内容拷贝一份到当下的文件当中,因此我们有必要考虑一个问题——如何避免头文件重复包含。
  相信很少有人会重复写两次#include "demo.h",但是,更常见的一种重复包含的情况是:有两个头文件first.h和second.h,其中second.h中有#include "first.h"。那么当main.c同时包含first.h和second.h的时候,实际上包含了两次first.h
  因此,我们可以通过条件编译来 避免重复包含。例如:编写一个头文件demo.h
#ifndef _DEMO_H
#define _DEMO_H
//宏定义
//typedef
//全局变量声明
//外部函数声明
#endif
四、为什么不可以在头文件中定义变量?
1、首先搞清楚编译的过程,流程图如下:
C源程序-->预编译处理(.c)-->编译、优化程序(.s、.asm)-->汇编程序(.obj、.o、.a、.ko)-->链接程序(.exe、.elf、.axf等)
对一个工程编译的时候,每个c文件都是单独编译的并得到对应的.o文件的,紧接着通过连接器把各个.o文件连接起来,最终生成统一的可执行文件。
2、假如一个工程当中,a.c和b.c都包含了同一个头文件demo.h,而demo.h里定义了变量——int var,即使我在demo.h里加了#ifndef和#endif来避免重复包含,但是编译还是会出错,编译器会说,a.o和b.o重定义了变量var。因为编译器编译的时候是分别对a.c和b.c编译的,这里并没有重复包含,但是却会分别在两个c文件定义完全相同的变量,连接器工作的时候就会发现错误并报错。
五、为什么要把函数声明写在头文件?
用一个例子说明:现在有三个文件main.c、test.c、test.h
/*****************main.c*****************/
#include <stdio.h>
#include "test.h"
int main(int argc, char *argv[])
{
    Function1();
    return 0;
}
/*****************end of main.c*****************/

/*****************test.c*****************/
#include "test.h"
void Function1(void)
{
    Function2();
}
void Function2(void)
{
    printf("Hello world!\n");
}
/*****************end of test.c*****************/

/*****************test.h*****************/
#ifndef _TEST_H
#define _TEST_H
void Function1(void);
void Function2(void);
#endif
/*****************end of test.h*****************/

  如上面所述,编译器会分别对main.c和test.c编译
  在编译main.c的时候,#include "test.h"把Function1()的声明拷贝到当前文件的对应位置, 则Function1()的作用域从当前的声明位置一直到c文件末尾。 如果去掉该#include语句,则Function1()在调用的时候还不在作用域内,因此编译器会报错。
  在编译test.c的时候,如果该c文件中只有一个函数Function2()且main.c只调用Function2()的时候,不写#include "test.h"也是可以的,因为分别编译后得到的main.o和test.o经过连接器的连接,main.o中调用Function2()的时候可以跳转到test.o的Function2()的函数体当中,这个连接过程是连接器自动搜索并实现的。(当然,这是一个不好的编程习惯)
  但是,如上面例程所示,当有两个函数Function1()和Function2()的时候,定义的先后不同,如果没有函数声明,则编译器则无法识别Function1()当中的Function2()。所以一般都要养成习惯,函数调用前都声明。
另外,对于Function2(),如果它仅供test.c内定义的函数调用的话,应该定义为static函数,并把test.h中的对应声明去掉,这样就对test.c以外的文件隐藏了它的实现细节,而且避免了不同c文件编写过程中出现的函数同名问题。
六、#include "头文件"一般是放在c文件中还是放在h文件中?
  除非h文件当中必须用到某些声明,否则尽量把#include放在c文件中,例如野火STM32开发板资料当中的摄像头例程。
  bsp_ov7725.c当中除了包含bsp_ov7725.h外,根据需要还包含了bsp_sccb.h和bsp_ili9341_lcd.h。
   而stm32f10x.h却被包含在bsp_ov7725.h中,因为在STM32例程当中,这个库常常用到。更重要的是,在bsp_ov7725.h的内容中包含了下图所示的GPIOA这些标识符,而这些标识符是在stm32f10x.h中声明的,因此stm32f10x.h必须被包含在bsp_ov7725.h中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

谈谈头文件 的相关文章

  • 是否可以将标准的纯 C 标头 #include 指令放入命名空间中? [复制]

    这个问题在这里已经有答案了 可能的重复 将 include 包装在命名空间块中是个好主意吗 https stackoverflow com questions 6670738 is it a good idea to wrap an inc
  • C和指针课后答案

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 第八章课后答案 提示 以下是本篇文章正文内容 下面案例可供参考
  • 带头双向循环链表基础

    带头双向循环链表基础 销毁 销毁 void ListDestory ListNode phead void ListDestory ListNode phead assert phead ListNode cur phead gt next
  • 可以拆分PHP配置文件php.ini吗?

    任何使用 php 的人都知道 php ini 是一个大文件 当您需要更改 ssh 时可能会让人头疼 例如我可以使用更改 nginx confinclude指令将启用站点的目录下的所有文件加载到主 nginx conf 中 所以我的问题很简单
  • JSP处理指令未关闭

    我试图将 HTML 文件包含到我的 JSP 中 但我的 Eclipse 显示了此错误 包含的文件 和错误 Processing instruction not closed 这只是简单的 JSP
  • 如何在 Visual Studio 中包含子目录?

    我必须包含许多头文件 它们位于不同的子目录中 Visual Studio 中是否有一种方法 我使用的是 2005 版 来设置一个包含路径 Visual Studio 也会在子目录中搜索头文件 从设计的角度来看 在 Visual Studio
  • linux/ext2_fs.h 有什么问题?

    猫主 c include
  • C++ 仅标头包含模式

    我想在 hpp 中编写代码 而不将 h 和 cpp 分开 我做到了 我仅将 cpp 用于静态类字段定义 我不想手动编写 include 如果可能的话 我使用前向声明 我的每个 hpp 文件都包含 pragma 一次 但是 当我的项目增长到
  • 为什么 Mac 上的 clang 会自动包含一些缺失的标头?

    我注意到clang 包括缺少的标头
  • 如何将参数传递给使用“include”呈现的PHP模板?

    需要 PHP 模板方面的帮助 我是 PHP 新手 我来自 Perl Embperl 无论如何 我的问题很简单 我有一个小模板来渲染一些项目 让它成为一篇博客文章 我知道使用此模板的唯一方法是使用 include 指令 我想在遍历所有相关博客
  • 一个文件夹中包含 100 万个或更多文件,用于包含(缓存)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我有一个 理论 问题 看看我正在计划的解决方案是否有意义 我有一个脚本 可以从数据库中读取大量数据 包括设置 配置等 并将其构建在一起 针对每个注册用
  • PHP 包含最佳实践问题

    我一直在学习 PHP 语法并进行练习 我有 NET 背景 因此母版页总是让我在处理页眉和页脚时变得非常简单 到目前为止 我有一个 mainHeader php 和 mainFooter php 其中有我的头部菜单和页脚 html 我创建了一
  • PHP 中可选包含

    我有一个包含常规配置的配置文件 在 git 存储库中 以及一个覆盖配置属性的本地配置文件 在存储库中被忽略 现在本地配置文件包含在配置文件的开头 include once local config php 但我希望包含是有条件的 仅当文件
  • 如何在 PHP 中包含一个类 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有文件index php 我想包含文件class twitter php在里面 我怎样才能做到这一点 希望当我将以下代码放入 index
  • 实体框架 - 包含在子查询中? - 第2部分

    我不确定这是否是正确的做法 我确信有人会告诉我是否正确 我问了一个问题 实体框架 包含在子查询中 https stackoverflow com questions 1662760 entity framework include in s
  • 为什么主要编译器对 stdint.h 使用 typedef 而对 stdbool.h 使用 #define?

    我刚刚注意到 gcc 和 clang 似乎都对 stdint h 使用 typedef 但对 stdbool h 使用 define 例子 clang 的 stdint h https clang llvm org doxygen stdi
  • PHP 解析包含

    我包括一个文件init php它定义路径常量 所以如果我包括init php在一个文件中 索引 php 然后在另一个文件中 布局 header php is init php在添加到这些文件之前进行解析 还是添加到父文件中 然后将父文件作为
  • 编译器处理包含保护头的开销有多大?

    为了加速大型源文件的编译 修剪翻译单元中使用的标头数量是否更有意义 或者编译代码的成本是否远远超过处理包含保护的时间标头 如果后者是真的 那么工程工作最好花在创建更多 轻量级的标头上 而不是更少 那么 现代编译器需要多长时间才能处理有效包含
  • Qt 的最佳实践包括和预编译头文件?

    当使用现代和最新的 C 编译器 例如 MSVC2015 并激活预编译头时 当前关于包含 Qt 头文件的 最佳实践 是什么 Example include
  • PHP include():文件大小和性能

    一个没有经验的PHP问题 我有一个 PHP 脚本文件 我需要在不同页面的很多地方多次包含该文件 我可以选择将包含的文件分解为几个较小的文件 并根据需要包含这些文件 或者 我可以将它们全部保存在一个 PHP 文件中 我想知道在这种情况下使用较

随机推荐

  • Paxos算法的java实现demo(只是为了简单的测试)

    Paxos 的概念我就不在这里啰嗦了 网上有很多优秀的博客 下面是我推荐的一个写的比较好的 https www cnblogs com linbingdong p 6253479 html 我们直接上代码吧 代码里面都有注释 先看一下项目结
  • 基于mulitisim14仿真的数字电子称

    参考了下面的文章做了一个数字电子称 https www renrendoc com paper 119413660 html 仿真如下 需要仿真文件的私聊
  • 中国工程院院士郑纬民:元宇宙是一个赋能实体经济的重要新赛道

    2022年3月31日 元宇宙产业委共同主席郑纬民院士在第三届元宇宙产业论坛发表了题为 元宇宙创新应用全面启航 算力是基础 的演讲 以下为郑纬民院士的演讲全文 今年全国两会中一些代表和委员提出了关于元宇宙的建议和提案 说明元宇宙已经得到了大家
  • 吉林大学超星MOOC学习通高级语言程序设计 C++ 实验04 数组及其在程序设计中的应用(2021级)(1)

    1 索引数组排序 题目编号 Exp04 Enhance04 GJBook3 06 21 题目名称 索引数组排序 题目描述 已知n n 100 个元素的整型数组 A 未排序 一个索引数组 B 保存 A 的下标 编写程序 在不改变数组A的情况下
  • Unikernels 解读

    转载于https zhuanlan zhihu com p 29053035 Unikernels Beyond Containers to the Next Generation of Cloud是 Russ Pavlicek的一本动物书
  • (Animator详解二)Unity Animator的基本属性

    在Inspector下 Animator的第一项为状态机的名称 注意 这里的名称不是动画名称 Tag 当前动画的Tag标签 可以通过Tag值来处理一些逻辑 Motion 动画片段的名称 Speed 动画的播放速度 1表示正常播放 speed
  • spring一些捞到的东西

    spring指令重排和多线程 原来在编写程序的时候要考虑这么多东西 要想清楚每一个代码 每一个线程在哪执行 还有要懂得jvm 的一些优化的 任重而道远啊 单例模式 只允许一个实例的存在 构造函数是私有的 对外提供获取实例的方法 getIns
  • CSS -网页动画

    目录 制作网页动画 1 CSS变形 2 CSS过渡 3 CSS动画 4 总结 制作网页动画 1 CSS变形 CSS3变形是一些效果的集合 如平移 旋转 缩放 倾斜效果 每个效果都可以称为变形 transform 它们可以分别操控元素发生平移
  • 第七十六篇 MIPI简单说明

    MIPI 移动行业处理器接口 是Mobile Industry Processor Interface的缩写 MIPI是MIPI联盟发起的为移动应用处理器制定的开放标准 目的是把手机内部的接口如摄像头 显示屏接口 射频 基带接口等标准化 从
  • c++之重载函数学习总结

    一 C 中的函数重载 1 函数重载的概念 用同一个函数名定义不同的函数 当函数名和不同的参数搭配时函数的含义不同 注意 在c语言中是没有函数重载这个概念的 代码示例演示 include
  • 用Flutter实现GaiaControl BLE OTA升级功能,支持Android/IOS

    代码基本移植官方GaiaControl Demo 支持RWCP 断点续传 设置蓝牙mtu 协议 这里主要分析GAIA CSR ble ota的过程 协议等等 希望对你有所帮助 这里对蓝牙服务特性订阅都不谈 读者自行了解 Gaia 是CSR
  • DM8锁查询及解决

    锁模拟 session1 与 session2同时对表t2的col1 200的列进行更新 但不提交 session1 SQL gt create table t1 col1 int SQL gt create table t2 col1 i
  • Select For update语句浅析

    Select forupdate语句是我们经常使用手工加锁语句 通常情况下 select语句是不会对数据加锁 妨碍影响其他的DML和DDL操作 同时 在多版本一致读机制的支持下 select语句也不会被其他类型语句所阻碍 借助for upd
  • chi square-卡方分布的定义及性质

    chi square 卡方分布的定义及性质 摘要 2 chi 2 2分布 卡方分布 的定义 g
  • Anchor-Free即插即用

    点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 后台回复 多模态综述 获取论文 后台回复 ECCV2022 获取ECCV2022所有自动驾驶方向论文 后台回复 领域综述 获取自动驾驶全栈近80篇综述论文 Anchor
  • 做什么副业比较靠谱,这五个正规项目,记得收藏

    人这一生不易 每个阶段都会有压力和烦恼 尤其是成年人 上有老下有小的 生活的重担都在一个人身上 压得人喘不过气 生活的方方面面都需要钱 仅靠工资已经很难维持一家人的开支了 所以很多人打算利用业余时间做点副业 来增加收入 可是不知道做什么 哪
  • Roaming\npm\node_modules\nrm\node_modules\open\index.js:38

    nrm1 2 1版本安装遇到的问题 C Users Cwqiang gt nrm ls C Users Cwqiang AppData Roaming npm node modules nrm node modules open index
  • ViewModel 的基本用法

    文章目录 ViewModel简介 ViewModel 的基本用法 向ViewModel传递参数 ViewModel简介 ViewModel 应该算是Jetpack 中最重要的组件之一了 其实Android 平台上之所以会出现注入MVP MV
  • 统一软件开发过程(RUP)分析

    什么是RUP RUP Rational Unified Process 统一软件开发过程 统一软件过程是一个面向对象且基于网络的程序开发方法论 RUP是风险驱动的 基于Use Case技术的 以架构为中心的 迭代的 可配置的软件开发流程 R
  • 谈谈头文件

    一 头文件的定义 C语言中常常使用预处理指令 include 把另一个文件的内容复制到源文件当中 被复制的文件就是头文件 其后缀名为 h 二 头文件的作用 1 在多文件的工程当中 头文件用于全局变量 外部函数的声明 其本身不包含程序的实现代