谈谈头文件

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 程序拆分为文件并包含?

    我组织了我的程序 将每个实体拆分在自己的文件中 是这样的 main c include student h include subject h include classroom h define PI 3 14 int sum int a
  • PHP 包含绝对路径

    我的网站上有一个名为 basePath 的变量 其设置为 basePath Systems dgw 我在所有 css js 和图像标签上使用它 为了更好的可见性而缩短 我对这些包含没有任何问题 它们在我所在的任何文件和文件夹中都可以正常工作
  • 项目参考条件包含多个条件

    这是我的 csproj 文件的片段
  • Django Include() 在 urls.py 中与两个应用程序

    我相信这是一个简单的问题 但我很难弄清楚为什么这不起作用 我有一个 django 项目 并且添加了第二个应用程序 销售 在第二个应用程序之前 我的 urls py 只是将所有内容路由到第一个应用程序 图表 如下所示 urlpatterns
  • 使用 Linq + Include 排序

    我与两个实体有一对多关系 Order int OrderId string OrderNumber OrderItem int ItemId int sequence Product int ProductId string Product
  • 编译器无法识别我的 C++ 类 - 循环依赖

    有这个基类 Core hpp ifndef C3 CORE HPP define C3 CORE HPP include
  • 保存 .php 文件并保存包含内容(可能)

    设置 我有一个标准 php 文件 index php 其中包含两个包含内容 一个用于页眉 header php 一个用于页脚 footer php index php 文件如下所示 索引 php h2 Hello h2 p class ed
  • 如何在函数中使用include?

    我有一个大函数 我希望仅在需要时加载 所以我认为使用 include 是正确的选择 但我还需要几个支持函数 仅在 go do it 中使用 如果它们位于包含的文件中 我会收到重新声明错误 参见示例 A 如果我将支持函数放在 include
  • 如何在 Yii 中安装 AWS SDK

    我想在我的 Yii 项目中使用适用于 PHP 的 Amazon AWS SDK 但是我收到各种包含错误 例如include CFCredentials php failed to open stream No such file or di
  • 像#include 这样的预处理器指令只能放在程序代码的顶部吗?

    我已经用过 pragma函数内的指令没有错误或警告 特别是 pragma pack 但是下面的代码显示了警告incompatible implicit declaration of built in function printf int
  • 如何在 PHP 中包含一个类 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有文件index php 我想包含文件class twitter php在里面 我怎样才能做到这一点 希望当我将以下代码放入 index
  • 经典 ASP #include virtual 不起作用

    我们正处于从 IIS6 2003 到 IIS8 2012 的迁移过程中 我们必须维护一些经典 ASP 以及 ASP 和 NET 应用程序 完整的应用程序似乎运行良好 例如 我进入 IIS 右键单击文件夹并执行 转换为应用程序 但我们的站点严
  • 为什么主要编译器对 stdint.h 使用 typedef 而对 stdbool.h 使用 #define?

    我刚刚注意到 gcc 和 clang 似乎都对 stdint h 使用 typedef 但对 stdbool h 使用 define 例子 clang 的 stdint h https clang llvm org doxygen stdi
  • “以下对象被‘package:xxx’屏蔽”是什么意思?

    当我加载包时 我收到一条消息 The following object is masked from package xxx 例如 如果我加载testthat http www rdocumentation org packages tes
  • PHP include():文件大小和性能

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

    我在这里找不到与此类似的问题 因为它非常复杂 我想更多的是烦恼而不是主要问题 如果这已经存在 我们深表歉意 我设置了一个名为 BOOST ROOT 的系统环境变量 它指向包含所有 boost 标头的目录 在我的例子中是 C Program
  • 描述 makefile 中的头文件位置

    在我正在开发的一个新项目中 我有以下目录结构 Project base src bin h Makefile 在我的源文件中 我包含如下内容 include h SomeHeaderFile h 而不是更正确的形式 include Some
  • XML 和 INI 哪个更快?

    我想知道 XML 是否比 INI 更快 反之亦然 我正在开发一个包含许多文件的网站 这个问题与我的问题有关关于包含许多文件 https stackoverflow com questions 7777522 too many include
  • 是否应该使用间接标头包含?

    如果一个项目的标头包含第二个标头 并且它们都包含一个公共标头 那么从第一个标头中删除公共标头的包含并依赖通过第二个标头的间接包含是一种好的做法吗 例如 我知道stdint h can被删除temperature h but should i
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include

随机推荐

  • 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 在多文件的工程当中 头文件用于全局变量 外部函数的声明 其本身不包含程序的实现代