C语言之头文件,预处理命令#include

news2024/9/21 4:33:33

0 为什么要添加头文件?为什么要使用头文件?

可以看下下面图片左边,是不使用头文件,假设我们为了实现某些功能,编写的函数,全部声明在主函数之前,写几个函数还行,如果是大型项目,哇,那么多函数全部写在一个文件里面,可能是有的是控制电源,有的是控制发送文字,这怎么后期管理啊

所以最好还是像右边一样,我们把这些自己编写的特定功能的函数(自己造的小轮子)拿出来,函数的定义,将功能类似的统一放在一个.c文件中,然后函数声明放在同名的.h文件中

然后在其他文件中或者包含main函数的文件中,#include添加对应的头文件即可完成在这个源文件中使用这个头文件对应的函数

1 基本概念

概念

头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义,被多个源文件中引用共享。

有两种类型的头文件:程序员编写的头文件编译器自带的头文件

在程序中要使用头文件,需要使用 C 预处理指令 #include 来引用它。前面我们已经看过 stdio.h 头文件,它是编译器自带的头文件。

引用头文件相当于复制头文件的内容,但是我们不会直接在源文件中复制头文件的内容,因为这么做很容易出错,特别在程序是由多个源文件组成的时候。

A simple practice in C 或 C++ 程序中,建议把所有的常量、宏、系统全局变量和函数原型写在头文件中,在需要的时候随时引用这些头文件。

 

2 使用方法

使用方法

<>或者“ ”

#include <you_use.h>

尖括号

<>

这种形式用于引用系统头文件。它在系统目录的标准列表中搜索名为 file 的文件。在编译源代码时,您可以通过 -I 选项把目录前置在该列表前。

双引号

“ ”

这种形式用于引用用户头文件。它在包含当前文件的目录中搜索名为 file 的文件。在编译源代码时,您可

以通过 -I 选项把目录前置在该列表前。

3 #include的过程实际是什么呢?

https://zhuanlan.zhihu.com/p/49543172

Linux:gcc工具_gcc -o-CSDN博客

请参考阅读这两个文章,会发现,#include 头文件后,实际上在预处理过程,就会把这些函数定义再拷贝一份到源文件。系统帮忙自动完成这个过程。

4 头文件中还可以包含多个头文件

一个xxx.h头文件中,还可以添加一个或者多个头文件,不止是可以添加在源文件中

有了前面对于#include 是"拷贝"的理解,应该不难理解为什么.h文件还可以继续放在.h文件中了

不再多做解释

5 防止编译多次的#ifndef用法

只引用一次头文件

如果一个头文件被引用两次,编译器会处理两次头文件的内容,这将产生错误。为了防止这种情况,标准的做法是把文件的整个内容放在条件编译语句中,如下:

#ifndef HEADER_FILE
#define HEADER_FILE

the entire header file file

#endif

这种结构就是通常所说的包装器 #ifndef。当再次引用头文件时,条件为假,因为 HEADER_FILE 已定义。此时,预处理器会跳过文件的整个内容,编译器会忽略它。

备注:小节5这段拷贝字菜鸟教程:C 头文件 | 菜鸟教程

6 我的一些QA


Q: 假设有一个my_class.c已经有了一些函数的定义,把函数声明放在了my_class.h中,为什么还要在my_class.c里面加上#include ”my_class.h“呢?因为一般不是在其他需要调用到my_class.c的函数的源文件里面才添加这个头文件嘛?

A:在 my_class.c 文件中包含 #include "my_class.h" 有以下几个重要原因:

一、确保函数声明的一致性

  1. 编译器检查

    • 当编译 my_class.c 文件时,编译器需要知道在这个文件中定义的函数的正确声明。虽然函数的定义在这个文件中,但编译器在处理每个源文件时是独立进行的。如果没有包含头文件,编译器可能无法确定函数的参数类型、返回值类型以及其他属性,从而导致编译错误。
    • 例如,如果在 my_class.h 中声明了一个函数 void myFunction(int arg);,而在 my_class.c 中定义了这个函数但没有包含头文件,编译器可能会认为这个函数的定义与其他地方的声明不一致,从而产生错误。
  2. 代码自洽性

    • 包含头文件可以确保 my_class.c 文件中的函数定义与头文件中的声明一致。如果在头文件中修改了函数的声明,例如改变了参数类型或返回值类型,那么包含头文件可以确保在编译 my_class.c 文件时能够检测到这种不一致性,并及时进行修正。
    • 比如,如果在开发过程中决定修改 myFunction 的参数类型,从 int 改为 double,那么在修改 my_class.h 中的声明后,如果 my_class.c 没有包含头文件,编译器可能不会检测到这个变化,从而导致在运行时出现错误。

二、方便代码维护和可读性

  1. 代码组织

    • 包含头文件可以使 my_class.c 文件的结构更加清晰,易于维护。开发人员可以在头文件中查看函数的声明,了解这个模块提供的接口,然后在对应的 .c 文件中找到函数的实现。这种分离有助于提高代码的可读性和可维护性。
    • 例如,当其他开发人员需要查看或修改 my_class.c 中的代码时,他们可以首先查看 my_class.h 头文件,了解这个模块的功能和接口,然后更容易地理解 .c 文件中的实现代码。
  2. 宏定义和类型定义

    • 头文件中通常不仅包含函数声明,还可能包含宏定义、类型定义、结构体声明等。在 my_class.c 文件中包含头文件可以确保能够正确使用这些定义。
    • 比如,如果在 my_class.h 中定义了一个宏 #define MAX_VALUE 100 或者一个结构体 typedef struct { int x; int y; } MyStruct;,那么在 my_class.c 文件中如果需要使用这些宏或结构体,就必须包含头文件。

总之,虽然在其他源文件中调用 my_class.c 中的函数时需要包含 my_class.h 头文件,但在 my_class.c 文件本身中也包含头文件是为了确保编译器能够正确处理这个文件中的函数定义,同时提高代码的可读性和可维护性。


Q:源文件的头文件一定要和他同名嘛?

A:在 C 和 C++ 中,源文件的头文件不一定要和它同名。

一、不同名的情况

  1. 反映功能而非文件名

    • 头文件的名称通常是为了反映其包含的内容或功能,而不一定与对应的源文件名称直接相关。
    • 例如,一个源文件名为calculator.c,它实现了各种数学计算功能,其头文件可以命名为math_operations.h,更清晰地表达了头文件中所包含的函数和数据结构是与数学运算相关的。
  2. 通用头文件

    • 有时候会有一些通用的头文件,它们可以被多个源文件包含,但并不与任何一个特定的源文件同名。
    • 比如,一个项目中有多个源文件都需要进行错误处理,那么可以有一个通用的头文件error_handling.h,被不同的源文件如main.cdata_processing.c等包含。
  3. 模块化设计

    • 在大型项目中,为了实现模块化设计,头文件的命名可能会遵循一定的命名规范,以反映模块的功能和层次结构,而不一定与源文件同名。
    • 例如,一个图形处理软件项目可能有不同的模块,如rendering(渲染)、geometry(几何)等。源文件rendering_module.c对应的头文件可能是rendering.h,源文件geometry_module.c对应的头文件可能是geometry.h

二、同名的情况

  1. 约定俗成

    • 在一些小型项目或简单的代码结构中,为了方便起见,人们可能会遵循源文件和头文件同名的约定。
    • 例如,源文件my_program.c对应的头文件为my_program.h。这种命名方式可以使开发者更容易找到对应的头文件和源文件。
  2. 清晰的对应关系

    • 同名的头文件和源文件可以提供一种清晰的对应关系,特别是在项目结构比较简单的情况下,方便开发者理解代码的组织方式。
    • 如果一个项目中有多个源文件和头文件,同名的方式可以让开发者更快地确定哪个头文件与哪个源文件对应。

总之,源文件的头文件名称可以根据项目的需求、代码结构和命名规范来确定,不一定与源文件同名。选择合适的头文件名称有助于提高代码的可读性、可维护性和可扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2118015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hadoop压缩技术与Hive文件格式详解

目录 文件格式和压缩 Hadoop压缩概述 压缩格式 Hive文件格式 Text File ORC 1&#xff09;文件格式 2&#xff09;结构 3&#xff09;建表语句 Parquet 1&#xff09;文件格式 2&#xff09;结构 3&#xff09;建表语句 压缩 Hive表数据进行压缩 1&#xff09;TextFil…

对话 IDC:一文带你了解低代码的技术趋势和平台选型

近日&#xff0c;葡萄城的活字格企业级低代码开发平台入选《中国低代码开发平台技术评估&#xff0c;2024》技术代表厂商&#xff0c;并在可视化开发、集成能力、开放性和兼容性以及生态能力维度获得五星评价。这一荣誉见证了葡萄城在低代码领域的技术实力与创新成果。 为进一…

Python 基本库用法:数学建模

文章目录 前言数据预处理——sklearn.preprocessing数据标准化数据归一化另一种数据预处理数据二值化异常值处理 numpy 相关用法跳过 nan 值的方法——nansum和nanmean展开多维数组&#xff08;变成类似list列表的形状&#xff09;重复一个数组——np.tile 分组聚集——pandas.…

不是你不想做 AI 产品,只是 UI 太贵劝退了你

"我有一个绝妙的 AI 产品创意!" "有想法就动起来呀~" "呃...还是算了吧,UI 太贵了,请不起" 相信不少人都有过这样的内心独白。 可能脑海中已经构思了无数个精彩的页面,甚至连细节都已经了然于胸。 但,在你准备大展拳脚的时候,现实给了…

鸿蒙开发5.0【弱引用】 使用

开发者需要依靠弱引用解决垃圾回收相关的内存管理问题。 强引用&#xff1a;默认的引用类型&#xff0c;被强引用的对象不会被垃圾回收。弱引用&#xff1a;允许对象在没有其他强引用时被垃圾回收&#xff0c;不会阻止垃圾回收器回收该对象。 场景一&#xff1a;使用弱引用打…

揭秘!老人帕金森与嗜睡之谜:是病症常态还是另有隐情?

在关爱老年人健康的道路上&#xff0c;帕金森病这一神经退行性疾病总是牵动着无数家庭的心。随着病情的发展&#xff0c;不少患者家属会发现&#xff0c;家里的老人似乎比以前更容易感到疲倦&#xff0c;甚至频繁出现嗜睡的情况。这不禁让人疑惑&#xff1a;老人帕金森会一直想…

数学建模——Box-Cox变换

用途&#xff1a;当某个随机变量 X X X 不服从正态分布的时候&#xff0c;可以尝试通过这种变换将其变成正态分布。 两个常用的变换 对数变换&#xff1a;已知随机变量 X X X&#xff0c;如果有 ln ⁡ X ∼ N ( μ , σ 2 ) \ln X\sim N(\mu,\sigma^2) lnX∼N(μ,σ2)&…

快被右下角的windows Defender烦死了,怎么让它消失?

前言 前段时间有小伙伴问&#xff1a;Windows自带的杀毒软件Windows Defender怎么关掉&#xff1f; 原因是无论在Windows Defender软件界面里怎么关闭&#xff0c;它都会拦截到某些软件和文件。 而且对于强迫症患者来说&#xff0c;右下角始终有个图标&#xff0c;还带了个x的…

【开源风云】从若依系列脚手架汲取编程之道(四)

&#x1f4d5;开源风云系列 &#x1f34a;本系列将从开源名将若依出发&#xff0c;探究优质开源项目脚手架汲取编程之道。 &#x1f349;从不分离版本开写到前后端分离版&#xff0c;再到微服务版本&#xff0c;乃至其中好玩的一系列增强Plus操作。 &#x1f348;希望你具备如下…

有了室内外一体化人行导航,你还怕迷路吗?

在快节奏的现代生活中&#xff0c;无论是穿梭于繁华的都市丛林&#xff0c;还是漫步于错综复杂的购物中心&#xff0c;迷路似乎成了不少人的“小确丧”。然而&#xff0c;随着科技的飞速发展&#xff0c;一项革命性的创新——室内外一体化人行导航系统&#xff0c;正悄然改变着…

CAN总线(一)

CAN总线&#xff08;Controller Area Network Bus&#xff09;&#xff0c;从名字上可以知道&#xff0c;CAN总线构建的是一种局域网网路&#xff0c;每个挂载在CAN总线上的设备都可以利用这个局域网去发送自己的消息&#xff0c;也可以接收局域网的各种消息&#xff0c;每个设…

解锁高效驱动密码:SiLM8260A系列SiLM8260ABCS-DG 集成米勒钳位的双通道隔离驱动芯片

附上SiLM8260A同系列型号参考&#xff1a; SiLM8260ADCS-DG 12.5V/11.5V SiLM8260ABCS-DG 8.5V/7.5V SiLM8260AACS-DG 5.5V/5V SiLM8260AGCS-DG 3.5V/3V SiLM8260ABCS-DG是一款集成了米勒钳位功能的双通道隔离驱动芯片&#xff0c;它精准地满足了上述严苛条件。具备…

Excel排序错误原因之一

# Excel日常表格中的文字排序乱了&#xff0c;在系统语言更改成英语之后&#xff0c;不再按照首字母的顺序排列&#xff0c;且强制设置序列顺序也无济于事。 Excel表格内的排序尝试 表格基础选项就有“排序”&#xff0c;在其自定义选项中的“选项”设置处设置“拼音排序”&am…

2024年实体行业都在用的AI自动直播,有哪些可以发展的机会?

抖捧AI自动直播系统&#xff0c;是一款结合Ai和短视频营销的自动化直播辅助工具&#xff0c;针对企业和实体店有多重的应用场景&#xff0c;通过预设的直播脚本和智能回复逻辑&#xff0c;实现不需要真人参与&#xff0c;就可以实现全天候24小时直播&#xff0c;当用户进入直播…

【Java基础】ThreadLocal<LoginUser>:存储登录用户信息

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【一篇文章搞定】LVGL显示中文+解决keil下LVGL无法正常显示中文及error:#8:missing closing quote问题

LVGL显示中文 进入lvgl中文文档&#xff1a;显示中文 — LVGL 文档 (100ask.net) 下载字体zip文件&#xff0c;解压得到一个.otf文件 进入LVGL的字体转换网站 Font Converter — LVGL 1.点击Browse指定.otf文件即可 2.range不用管 3.为了节省内存在Symbols中输入自己要使用的…

【计算机网络】概述篇

目录 导学 计算机网络的发展简史 互联网的发展历史 中国互联网的发展历史 计算机网络的层次结构 层次结构设计的基本原则 OSI七层模型 TCP/IP四层模型 现代互联网的网络拓扑 计算机网络的性能指标 速率 时延 发送时延 ​传播时延 ​排队时延 处理时延 总时延 …

K8S - Emptydir - 取代ELK 使用fluentd 构建logging saidcar

由于k8s 的无状态service 通常部署在多个POD中&#xff0c; 实现多实例面向高并发。 但是k8s 本身并没有提供集中查询多个pod的日志的功能 其中1个常见方案就是ELK. 本文的方案是 利用fluentd sidecar 和 emptydir 把多个pod的日志导向到bigquery的table中。 Emptydir 的简介 …

STM32F407ZGT6单片机HAL库——DAC输出

一、输出直流电压 1.cubemax的配置&#xff08;通道1&#xff09; 2.直流电压大小计算 3.主函数加入初始化的程序 float DAC_voltage1.5;HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, DAC_voltage*4095/3.3);//HAL_DAC_Start(&hdac,DAC_CHANNEL_1); 二、…

深度解析价值流:推动业务架构创新与效益提升的核心指南

数字化转型下的价值流管理与架构 在当今的数字化转型背景下&#xff0c;如何有效创造并交付价值&#xff0c;成为企业竞争力提升的关键课题。作为企业架构的重要组成部分&#xff0c;价值流的概念为业务决策者和技术人员提供了全面的工具&#xff0c;帮助优化业务能力&#xf…