【转】关于C/C++语言中头文件的使用的一些看法

本文详细介绍了C语言中如何组织和使用多个源代码文件及头文件,解释了头文件的作用和正确的使用方法。

一、  只有一个文件的情况

先来看一下比较简单的情形,也就是只有一个文件的时候,一个程序是什么样子的。

//main.c

#include <stdio.h>

 

int main(int argc, char** args)

{

    printf("Hello/n") ;

    return 0 ;

}

这个时候程序一目了然,我们很容易就可以看出它说了什么。

 

二、  多个源代码文件的情况

但是,随着我们要编写的程序的规模不断扩大,我们不得不把一个源代码文件拆分开,把具有一定功能的某些方法放到其它单独的源码文件中。比如像下面这样:

//main.c

#include <stdio.h>

 

int main(int argc, char** args)

{

    sayhello() ;

    return 0 ;

}

 

//sayhello.c

#include <stdio.h>

int sayhello()

{

    printf("Hello/n") ;

}

把功能放在了sayhello.c文件中,而main.c只放主函数的代码。这样看起来更加的清晰明快。虽然形式上分成多个文件,但编译器在编译的时候会自动把它们连在一起,也就是说它们还是相当于在一个大文件中写代码。但是如果我们启图分别编译这两个文件,然后再链接成一个可执行程序的时候,就会发生错误。原因在于main.c中使用了一个函数sayhello,这时编译器并不知道sayhello是什么,因为相对于main.c来说,它并不存在sayhello的定义和实现。所以,我们必须要在main.c中加入sayhello的声明(只要声明就够了,不必再实现一次)。方法是加一句“int sayhello() ;”但问题是,当我们的工程越来越大的时候,我们总不能引用一个函数就写一下它的都声明吧?

三、  引入头文件

这时最好的解决办法就是引用头文件。就是编写一个与sayhello.c同名的文件sayhello.h,用于定义常量、结构,声明函数等。具体的做法如下:

//main.c

#include <stdio.h>

#include "sayhello.h"

 

int main(int argc, char** args)

{

    sayhello() ;

    return 0 ;

}

 

//sayhello.c

#include <stdio.h>

#include "sayhello.h"

int sayhello()

{

    printf("Hello/n") ;

}

 

//sayhello.h

int sayhello() ;

 

四、  说说include宏

对于头文件,我们应仅把它看作是一个文本文件,它跟程序的代码文件(即扩展名为.c的文件)并不一样。编译器在编译的过程中,只会处理代码文件,而不会去管其它的头文件。只有当我们在头文件中使用#include的时候,相应的头文件才会被包含进来。编译器只是在编译前把#include所在的位置换成了相应头文件中的内容罢了。

使用<>括起来的是系统的默认库文件,也就是说不用咱们自己去找这个文件所在的位置,只写一个名字,编译器就自动找到库目录中的文件了。而””括起来的正好相反,大多是我们自己编的代码或引用的非标准C的库文件,它要求给出文件所在的绝对地址或相对地址。比如说,如果你的库目录设成/usr/share/include,那么下面的写法是等价的:

#include <stdio.h> == #include “/usr/share/include/stdio.h”

 

五、  谈谈头文件具体的使用

道理都懂了,那么自己写程序时,我的头文件到底应该怎么写呢?其实,头文件的写法很随意,很多人都有自己的使用习惯。但是我自己的看法是,尽量模仿标准C的库。现在就来研究一下吧。

比如我们平时使用printf时,我们都要包括一个头文件,即stdio.h。它的特点是我在哪个代码文件用到了这个库中的函数,我就在哪个代码文件中包括它的头文件;包含它后,我的代码中不应该引入错误,引用的库函数不应该因为代码文件中多引用了或少引用了一些其它的头文件而出错。

为了达到这个目标,我的做法是:每写一个代码文件,就写一个对应的头文件;把所有的声明、定义、结构体、常量、宏放在头文件中,而代码实现绝对不放在头文件中;对头文件的抱含也放到头文件中,代码文件中不含include宏。

下面看一些反例:

反例1:

//types.h

typedef int status ;

 

//sayhello.h

status sayhello() ;

 

//sayhello.c

#include <stdio.h>

#include "types.h"

#include "sayhello.h"

 

status sayhello()

{

    printf("Hello!/n") ;

    return 0 ;

}

 

//main.c

#include "sayhello.h"

 

int main(int argc, char** argv)

{

    sayhello() ;

    return 0 ;

}

在sayhello的定义中,出现了一个自定义类型status,它的声明包括在types.h文件中。放对它的引用放在了sayhello.c中,这样单独编译sayhello.c没有任何问题。可是当编译到main.c的时候,就出现问题了,编译报错:找不到status的声明。这是因为在main.c中只抱括了sayhello.h,而它的声明又需要types.h。所以,它出现了由于少引用types.h而发生的错误。所以,我强调把所有的include都放到头文件中去。如果这样写则不会出问题。

//sayhello.h

#include <stdio.h>

#include "types.h"

 

status sayhello() ;

 

//sayhello.c

#include "sayhello.h"

 

status sayhello()

{

    printf("Hello!/n") ;

    return 0 ;

}

//main.c

#include "sayhello.h"

 

int main(int argc, char** argv)

{

    sayhello() ;

    return 0 ;

}

这样就符合了前面提到的原则。不过,我还可以做如下的改动:

//main.c

#include "sayhello.h"

#include "types.h"

 

int main(int argc, char** argv)

{

    status s = sayhello() ;

    return 0 ;

}

在主程序中声明了status类型的变量s。根据上面的原则,哪里引用了它,哪里就包括它的头文件,所以我们包括了types.h头文件。有人会说:“没有types.h,也一样不会出错啊,在sayhello.h中不是引用过types.h吗?”这样做真的是多此一举吗?当然不是,我觉得它是相当有意义的。第一,它维护了我们自己定下的原则。保持一个不变的代码习惯是很有好处的。第二,由于我们保证了头文件中不加入实现性质的代码,只写些声明类的代码,它们在编译时只是起来语法制导的作用,并不会被成为目标程序的一部分,所以这样写并不会造成浪费。这也是提倡头文件中不要夹杂代码的一个原因。

如果真的不想把头文件编译多次的话,还有一个办法,如下:

#ifndef _HEADER_FILE_

#define _HEADER_FILE_

//声明部分

//...........

#endif

这样写可以保证编译器只编译一次,其中的_HEADER_FILE_自己定义的头文件的唯一标识,只要别跟常量定义和别的头文件冲突,您喜欢叫它什么就叫它什么吧。^^

 

六、  总结

最后总结一下吧。如果当你在编写自己庞大的代码文件群的时候,遇到了一些犹豫,就想想上面的原则和应用。当因为头文件编译出错的时候,考虑一下是否自己有哪些动作违反了上面的原则。只要经常思考,每个人都会总结是适合自己的使用习惯,尽量减少在这些程序员看来无关紧要的事情上出错的机会。以上只是本人自己使用习惯的一次总结,不代表任何规范和标准,欢迎善意的批评指正.^_^

先展示下效果 https://pan.quark.cn/s/e81b877737c1 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 执行环境,它使开发者能够在服务器端执行 JavaScript 编程,显著促进了全栈开发的应用普及。 在 Node.js 的开发流程中,`node_modules` 文件夹用于存储所有依赖的模块,随着项目的进展,该文件夹可能会变得异常庞大,其中包含了众多可能已不再需要的文件和文件夹,这不仅会消耗大量的硬盘空间,还可能减慢项目的加载时间。 `ModClean 2.0` 正是为了应对这一挑战而设计的工具。 `ModClean` 是一款用于清理 `node_modules` 的软件,其核心功能是移除那些不再被使用的文件和文件夹,从而确保项目的整洁性和运行效率。 `ModClean 2.0` 是此工具的改进版本,在原有功能上增加了更多特性,从而提高了清理工作的效率和精确度。 在 `ModClean 2.0` 中,用户可以设置清理规则,例如排除特定的模块或文件类型,以防止误删重要文件。 该工具通常会保留项目所依赖的核心模块,但会移除测试、文档、示例代码等非运行时必需的部分。 通过这种方式,`ModClean` 能够协助开发者优化项目结构,减少不必要的依赖,加快项目的构建速度。 使用 `ModClean` 的步骤大致如下:1. 需要先安装 `ModClean`,在项目的根目录中执行以下命令: ``` npm install modclean -g ```2. 创建配置文件 `.modcleanrc.json` 或 `.modcleanrc.js`,设定希望清理的规则。 比如,可能需要忽略 `LICENSE` 文件或整个 `docs`...
2026最新微信在线AI客服系统源码 微信客服AI系统是一款基于PHP开发的智能客服解决方案,完美集成企业微信客服,为企业提供7×24小时智能客服服务。系统支持文本对话、图片分析、视频分析等多种交互方式,并具备完善的对话管理、人工接、咨询提醒等高级功能。 核心功能 ### 1.  智能AI客服 #### 自动回复 - **上下文理解**:系统自动保存用户对话历史,AI能够理解上下文,提供连贯的对话体验 - **个性化配置**:可自定义系统提示词、最大输出长度等AI参数 #### 产品知识库集成 - **公司信息**:支持配置公司简介、官网、竞争对手等信息 - **产品列表**:可添加多个产品,包括产品名称、配置、价格、适用人群、特点等 - **常见问题FAQ**:预设常见问题及答案,AI优先使用知识库内容回答 - **促销活动**:支持配置当前优惠活动,AI会自动向用户推荐 ### 2. 多媒体支持 #### 图片分析 - 支持用户发送图片,AI自动分析图片内容 - 可结合文字描述,提供更精准的分析结果 - 支持常见图片格式:JPG、PNG、GIF、WebP等 #### 视频分析 - 支持用户发送视频,AI自动分析视频内容 - 视频文件自动保存到服务器,提供公网访问 - 支持常见视频格式:MP4、等 ### 3.  人工客服接 #### 关键词触发 - **自定义关键词**:可配置多个人工触发关键词(如:人工、客服、人工等) - **自动接**:用户消息包含关键词时,自动接给指定人工客服 - **友好提示**:接前向用户发送提示消息,提升用户体验 #### 一键介入功能 - **后台管理**:管理员可在对话管理页面查看所有对话记录 - **快速接**:点击"一键介入"按钮,立即将用户接给人工客服
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值