C语言头文件编程,C语言编程规范-头文件(Day2)

2023-05-16

1 头文件

背景

对于C语言来说,头文件的设计体现了大部分的系统设计。不合理的头文件布局是编译时间过长的根本原因,不合理的头文件实际上是不合理的设计。

术语定义

依赖:本章节特指编译依赖。若x.h包含y.h,则称作x依赖y。依赖关系会会进行传导,如x.h包含y.h,y.h又包含了z.h,则x通过y依赖了z。虽然依赖是不可避免的,也是必须的,但是不良的设计会导致整个系统的依赖关系无比复杂,使得任意一个文件的修改都要重新编译整个系统,导致编译时间剧增。

在一个设计良好的系统中,修改一个文件,只需要重新编译数个,甚至是一个文件。

头文件依赖:若包含头文件aa.h,则就引入了新的依赖:一旦aa.h被修改,任何直接和间接包含aa.h代码都会被重新编译。如果aa.h又包含了其它头文件如bb.h,那么bb.h的任何改变都将导致所有包含了aa.h的代码被重新编译,在敏捷开发方式下,代码被频繁构建,漫长的编译时间将极大的阻碍频繁构建。因此,我们倾向与减少包含头文件,尤其是在头文件中包含头文件,以控制改动代码后的编译时间。

原则1.1 头文件中适合放置接口的声明,不适合放置实现。

说明:头文件是模块(Module)或单元(Unit)的对外接口头文件应放置对外部的声明,如对外部提供的函数声明、宏定义、类型定义等。

内部使用的函数(相当于类的私有方法)声明不应该放在头文件中。

内部使用的宏、枚举、结构定义不应放入头文件中。

变量定义不应放在头文件中,应放在.c文件中。

变量的声明尽量不要放在头文件中,亦即尽量不要使用全局变量作为接口。变量是模块或但单元的内部实现细节,不应通过在头文件中声明的方式直接暴露给外部,应通过函数接口的方式进行对外暴露。即使必须使用全局变量,也应只在.c中定义全局变量,在.h中仅声明变量为全局的。

原则1.2 头文件应当职责单一

说明:头文件过于复杂,依赖过于复杂是导致编译时间过长的主要原因。很多现有代码中头文件过大,职责过多,再加上循环依赖的问题,可能导致为了在.c中使用一个宏,而包含十几个头文件。这样会导致某些头文件可能被不必要的展开很多次,大大增加了工程的编译时间。

原则1.3 头文件应向稳定的方向包含。

说明:头文件的包含关系是一种依赖,一般来说,应当让不稳定的模块依赖稳定的模块,从而当不稳定的模块发生变化时,不会影响(编译)稳定的模块。

就我们的产品而言,依赖的方向应该是:产品依赖于平台,平台依赖于标准库。如果产品线平台的代码中已经包含了产品的头文件,导致平台不发单独编译、发布和测试,是非常糟糕的。

除了不稳定的模块依赖于稳定的模块外,更好地方式是两个模块共同依赖于接口。这样任何一个模块的内部实现更改都不需要重新编译另外一个模块。在这里,我们假设接口本身是最稳定的。

推荐开发人员使用“依赖倒置”原则,即由使用者制定接口,服务提供者实现接口。

规则1.1 每一个.c文件应有一个同名.h文件,用于声明需要对外公开的接口。

说明:如果一个.c文件不需要对外公布任何接口,则其就不应当存在,除非它是程序的入口,如main函数所在的文件。

示例:对于如下场景,如在一个.c中存在函数调用关系:

void foo()

{

bar();

{

void bar()

{

Do something;

}

必须在foo之前声明bar,否则会导致编译错误。

这一类函数声明,应当在.c的头部声明,并声明为static的,如下:

static void bar();

void foo()

{

bar();

}

void bar()

{

Do something;

}

规则1.2 禁止头文件循环依赖。

说明:头文件循环依赖,指a.h包含b.h,b.h包含c.h,c.h包含a.h之类导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。而如果是单向依赖,如a.h包含b.h,b.h包含c.h,而c.h不包含任何头文件,则修改a.h不会导致包含了b.h、c.h的源代码重新编译。

规则1.3 .c/.h文件禁止包含用不到的头文件。

说明:很多系统中头文件包含关系复杂,开发人员为了省事起见,不会一一钻研,直接包含一切想到的头文件,导致整个系统的编译时间进一步恶化,并对后期维护造成麻烦。

规则1.4 头文件应当自包含。

说明:简单的说,自包含就是任意一个头文件均可独立编译。如果一个文件包含某个头文件,还要包含另外一个头文件才能工作的话,就会增加交流障碍,给这个头文件的用户添加不必要的负担。

示例:

如果a.h不是自包含的,需要包含b.h才能编译,会带来危害:

每个使用a.h头文件的.c文件,为了让引入的a.h的内容编译通过,都要包含额外的头文件b.h。

额外的头文件b.h必须在a.h之前进行包含,这在包含顺序上产生了依赖。

规则1.5 总是编写内部的#include保护符(#define保护)。

说明:多次包含一个头文件可以通过认真的设计来避免。如果做不到这一点,就要采取阻止头文件内容被包含多于一次的机制。

通常的手段是为每个文件配置一个宏,当头文件第一次被包含时就定义这个宏,并在头文件被再次包含时使用它以排除文件内容。

所有的头文件都应当使用#define放置头文件被多重包含,命名格式为FILENAME_H,为保证唯一性,更好地命名是PROJECTNAME_PATH_FILENAME_H.

注:没有在宏的最前面加上“_”,即使用FILENAME_H代替_FILENAME_H,是因为一般以“_”和“__”开头的标识符为系统保留或标准库使用,在有些静态检查工具中,若全局可见的标识符以“_”开头会给出报警。

定义包含保护符时,应该遵循如下规则:

1)保护符使用唯一名称;

2)不要再受保护部分的前后放置代码或注释。

示例:假定VOS工程的timer模块的timer.h,其目录VOS/timer/timer.h,应按如下方式保护:

#ifndef VOS_INCLUDE_TIMER_TIMER_H

#define VOS_INCLUDE_TIMER_TIMER_H

...

#endif

也可以使用如下简单方式保护:

#ifndef TIMER_H

#define TIMER_H

...

#endif

例外情况:头文件的版权声明部分以及头文件的整体注释部分(如阐述此头文件的开发背景、使用注意事项等)可以放在保护符(#ifndef XX_H)前面。

规则1.6 禁止在头文件中定义变量。

说明:在头文件中定义变量,将会由于头文件被其他.c文件包含而导致变量重复定义。

规则1.7 只能通过包含头文件的方式使用其他.c提供的接口,禁止在.c中通过extern的方式使用外部函数接口、变量。

说明:若A.c使用了B.c定义的foo()函数,则应当在B.h中声明extern int foo(int intput);并在A.c中通过#include 来使用foo。禁止通过在A.c中直接写extern int foo(int input);来使用foo,后面这种写法容易在foo改变时可能导致声明和定义不一致。

规则1.8 禁止在extern “C”中包含头文件。

说明:在extern “C”中包含头文件,会导致extern “C”嵌套,Visual Studio对extern “C”嵌套层次有限制,嵌套层次太多会编译错误。

示例:错误的使用方式:

extern "C"

{

#include "xxx.h"...

}

正确的使用方式:

#include "xxx.h"

extern "C"

{

...

}

建议1.1 一个模块通常包含多个.c文件,建议放在同一个目录下,目录名即为模块名。为方便外部使用者,建议每个模块提供一个.h,文件名为目录名。

说明:需要注意的是,这个.h并不是简单的包含所有内部的.h,它是为了模块使用者的方便,对外整体提供的模块接口。

建议1.2 如果一个模块包含多个子模块,则建议每个子模块提供一个对外的.h,文件名为子模块名。

说明:降低接口使用者的编写难度。

建议1.3 头文件不要使用非习惯用法的拓展名,如.inc。

建议1.4 同一产品统一包含头文件排列方式。

说明:常见的包含头文件排列方式:功能块排序、文件名升序、稳定度排序。

示例1:

以升序方式排列头文件可以避免头文件被重复包含,如:

#include

#include

#include

#include

示例2:

以稳定度排序,建议将不稳定的头文件放在前面,如把产品的头文件放在平台的头文件前面,如下:

#include

#include

相对来说,product.h的修改较为频繁,如果有错误,不必编译platform.h就可以发现product.h的错误,可以部分减少编译时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言头文件编程,C语言编程规范-头文件(Day2) 的相关文章

  • MODBUS MASTER RTU在STM32上的实现

    MODBUS MASTER RTU在STM32上的实现 1 概述 最近需要将几个信号采集模块通过总线串联起来 xff0c 这样便于系统模块化 故将目光关注到了工业上经常使用的modbus协议 modbus协议是一种一主多从的拓扑结构 xff
  • 基于HttpClient的HttpUtils(后台访问URL)

    最近做在线支付时遇到需要以后台方式访问URL并获取其返回的数据的问题 xff0c 在网络上g了一把 xff0c 发现在常用的还是Apache的HttpClient 因为以经常要用到的原故 xff0c 因此我对其进行了一些简单的封装 xff0
  • micropython安装ros_ROS2与STM32入门教程-microROS的freertos版本

    ROS2与STM32入门教程 micro ros的freertos版本 说明 xff1a 介绍如何安装使用micro ros 测试开发板 xff1a olimex stm32 e407 步骤 xff1a 安装ros2版本foxy xff0c
  • C#中通过com组件操作excel不能关闭的问题

    问题 xff1a 当用如下代码操作完Excel xff0c 虽然调用了Application的Quit 方法 xff0c 但发现Excel进程并没退出 object missing 61 System Reflection Missing
  • 交叉编译的概念及交叉编译工具的安装

    目录 一 什么是交叉编译 二 为什么要交叉编译 xff1f 三 交叉编译链的安装 四 相关使用方法 五 软连接 一 什么是交叉编译 交叉编译是指将一种编程语言编写的程序编译成另一种编程语言的程序 xff0c 通常是在不同的操作系统或硬件环境
  • .cn根服务器被攻击之后

    如果是互联网行业的人员应该知道 xff0c 8月25日凌晨 xff0c 大批的 cn 域名的网站都无法访问 xff0c 当然包括weibo cn等大型网站 个人比较奇怪的一件事情是 xff0c 微博PC网页版是 www weibo com
  • [UML]UML系列——包图Package

    系列文章 UML UML系列 用例图Use Case UML UML系列 用例图中的各种关系 xff08 include extend xff09 UML UML系列 类图Class UML UML系列 类图class的关联关系 xff08
  • VBA编程中的 sheet1 与 sheets(1)的区别

    自己理解 sheet1是一个专有名词 xff0c 不是任何对象的属性 xff0c 只能单独使用 xff0c 特指代码所在工作簿的那个sheet1 和顺序无关 xff0c 是固定的一个表 xff0c sheets 1 则和顺序有关 参考资料
  • python练习笔记——计算1/1-1/3+1/5-1/7……的和

    1 1 1 3 43 1 5 1 7 43 求100000个这样的分式计算之为是多少 xff1f 将此值乘以4后打印出来 xff0c 看看是什么 xff1f num list 61 count 61 1 i 61 1 while True
  • Django Model获取指定列的数据

    model一般都是有多个属性的 xff0c 但是很多时候我们又只需要查询特定的某一个 xff0c 这个时候可以用到values和values list 利用values查询 from attendence models import Emp
  • HIVE自定义函数的扩展

    作者简介 淳敏 xff0c 物流架构师同时也是一位team leader xff0c 工作认真负责 xff0c 曾在休假期间 面向大海编程 xff0c 不明觉厉 在Hive中 xff0c 用户可以自定义一些函数 xff0c 用于扩展Hive
  • Flink Window分析及Watermark解决乱序数据机制深入剖析-Flink牛刀小试

    版权声明 xff1a 本套技术专栏是作者 xff08 秦凯新 xff09 平时工作的总结和升华 xff0c 通过从真实商业环境抽取案例进行总结和分享 xff0c 并给出商业应用的调优建议和集群环境容量规划等内容 xff0c 请持续关注本套博
  • 使用Network Recycle Bin启用映射网络驱动器上的回收站

    前言 在内网环境中我们经常会使用NAS或者Samba在Windows中映射网络驱动器 xff0c 方便局域网用户实时共享交换数据 但当存储在网络或映射网络上的任何文件被删除时 xff0c 该文件将被永久删除 它不会去到本地计算机回收站 xf
  • 为强化机器学习性能,ARM推出两款新GPU Mali-G52和Mali-G31

    ARM于近期推出了两款图形处理器产品 xff0c 分别为Mali G52以及Mali G31 xff0c 主要应用于主流移动市场 由于移动端AI计算 图形处理需求的与日俱增 xff0c GPU之于手机SoC的作用日渐凸显 xff0c ARM
  • 判断python字典某个键的值是否为空

    2019独角兽企业重金招聘Python工程师标准 gt gt gt code if dict get key 0 61 61 0 值即为空 code 转载于 https my oschina net u 2254175 blog 37213
  • javascript中的==和===

    判断两个变量是否相等是程序设计中非常重要的运算 在处理原始值时 xff0c 这种运算相当简单 xff0c 但涉及对 象 xff0c 任务就稍有点复杂 ECMAScript提供了两套运算符处理这个问题 xff0c 等号和非等号用于处理原始值
  • 如何检测资源泄露

    Window上我们常见的资源泄露包括内存和对象句柄泄露 xff0c 下面讨论下对各类泄露的检测方法 关于内存泄漏 xff0c 我以前写过2篇文章 xff1a C 43 43 中基于Crt的内存泄漏检测 xff0c 基于WinDbg的内存泄漏
  • WPF触屏Touch事件在嵌套控件中的响应问题

    前几天遇到个touch事件的坑 xff0c 记录下来以增强理解 具体是 想把一个listview嵌套到另一个listview xff0c 这时候如果list view xff08 子listview xff09 的内容过多超过容器高度 xf
  • 设计模式-工厂模式

    xl echo编辑整理 xff0c 欢迎转载 xff0c 转载请声明文章来源 欢迎添加echo微信 微信号 xff1a t2421499075 进行交流学习 百战不败 xff0c 依不自称常胜 xff0c 百败不颓 xff0c 依能奋力前行
  • IBM AIX5.3 linux下C/C++实现HTTPS接口

    最近在工作中需要开发一个Https接口 xff0c 其不同于http soap等协议 xff0c 可以直接组织报文并发送 xff0c 不存在加密 xff0c 认证和获取密钥等安全操作 且之前开发的项目没有开发过这类接口 xff0c 所以当时

随机推荐

  • c语言把网络字节序转换成小端,网络编程字节序转换问题

    一 xff1a 大小端 一 大小端区别 字节 区别是依据 xff1a 计算机系统在存储数据时起始地址是高地址仍是低地址 小端 xff1a 从低地址开始存储 大端 xff1a 从高地址开始存储 补充 xff1a 这里大小端是按字节区别的 xf
  • [转载]Linux C 字符串函数 sprintf()、snprintf() 详解

    一 sprintf 函数详解 在将各种类 型的数据构造成字符串时 xff0c sprintf 的强大功能很少会让你失望 由于 sprintf 跟 printf 在用法上几乎一样 xff0c 只是打印的目的地不同而已 xff0c 前者打印到字
  • http Authorization

    MDN 文档 HTTP协议中的 Authorization 请求消息头含有服务器用于验证用户代理身份的凭证 xff0c 通常会在服务器返回401 Authorization lt type gt lt credentials gt curl
  • linux编译动态库未定义,GCC链接库的一个坑:动态库存在却提示未定义动态库的函数...

    背景 在GCC中已经指定链接库 xff0c 然而编译时却提示动态库函数未定义 xff01 测试出现的错误提示如下 xff1a GMPY 64 13 48 tmp gcc o test L lmylib test c tmp ccysQZI3
  • .inf右键没有安装菜单项解决办法

    打开我的电脑 xff0c 工具菜单中的文件夹选项 切换至文件类型选项卡 xff0c 在其中找到inf文件 xff0c 点高级按钮 xff0c 双击安装 I xff0c 没有新建一个 按如下内容修 改 用于执行操作的应用程序C WINDOWS
  • C++ : 编译单元、声明和定义、头文件作用、防止头文件在同一个编译单元重复引用、static和不具名空间...

    转 自 xff1a http www cnblogs com rocketfan archive 2009 10 02 1577361 html 1 编译单元 xff1a 一个 cc或 cpp文件作为一个编译单元 xff0c 生成 o 2
  • request方法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1request概述 request是Servlet service 方法的一个参数 xff0c 类型为javax servlet http HttpServletRequ
  • Eclipse调试:改变颜色, 背景与字体大小 和xml字体调整

    Eclipse背景颜色修改 xff1a 操作界面默认颜色为白色 对于我们长期使用电脑编程的人来说 xff0c 白色很刺激我们的眼睛 xff0c 所以我经常会改变workspace的背景色 xff0c 使眼睛舒服一些 设置方法如下 xff1a
  • ASM汇编常用跳转指令-极速查

    作者 xff1a 逆向驿站 微信公众号 xff1a 逆向驿站 知乎 xff1a 逆向驿站 若不是老鸟 xff0c 是不是经常为各种JXX汇编跳转指令查资料 xff1f 影响效率 xff0c 更影响潜意识整体分析的 34 灵光一现 34 本公
  • Android签名机制及原理

    Android签名机制及原理 Android系统在安装APK的时候 xff0c 首先会检验APK的签名 xff0c 如果发现签名文件不存在或者校验签名失败 xff0c 则会拒绝安装 xff0c 所以应用程序在发布之前一定要进行签名 给APK
  • chrome扩展获取页面dom对象信息

    chrome扩展 xff0c 在popup页面 xff0c 给页面对象绑定点击事件 xff0c 获取当前tab加载页面的DOM对象信息 本chrome扩展功能主要用于获取百度搜索输入框中用户输入的关键字 效果如下 源代码如下 注意 xff1
  • CentOS 7之FirewallD与iptables的区别

    2019独角兽企业重金招聘Python工程师标准 gt gt gt FirewallD 即Dynamic Firewall Manager of Linux systems xff0c Linux系统的动态防火墙管理器 xff0c 是 ip
  • goland编辑器护眼背景颜色设置

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 打开goland软件 菜单栏 file settings 打开如下 搞定 色调 xff1a 85 xff1b 饱和度 xff1a 123 xff1b 亮度 xff1a 20
  • 让IE8支持HTML5及canvas功能!

    让IE8支持HTML5及canvas功能 xff01 微软出的IE9支持HTML5 xff0c 但因为不支持XP系统 xff0c 暂时我还用不了 即使能用 xff0c 现阶段如果开发HTML5页面 xff0c 并考虑到兼容性问题的话 xff
  • 卷积神经网络(CNN)的训练过程

    卷积神经网络的训练过程 卷积神经网络的训练过程分为两个阶段 第一个阶段是数据由低层次向高层次传播的阶段 xff0c 即前向传播阶段 另外一个阶段是 xff0c 当前向传播得出的结果与预期不相符时 xff0c 将误差从高层次向底层次进行传播训
  • 编程常用英语词汇大全

    编程常用英语词汇大全 很实用的编程英语词库 xff0c 共收录一千五百余条词汇 第一部分 xff1a application 应用程式 应用 应用程序 application framework 应用程式框架 应用框架 应用程序框架 arc
  • [LTMP搭建] Centos 6.5 安装配置 Tengine

    接上篇 xff1a http www cnblogs com antarctican p 3752812 html 安装PHP 一 安装依赖的扩展 记得前几天编译tengine xff0c 不使用 with http lua module
  • .net项目移植后的虚拟目录的配置问题

    VS NET 2003 开发环境打开此项目 xff08 MyWeb xff09 时 xff0c 出现如果如下问题 xff1a 无法从 Web 服务器获取项目文件 无法打开 Web 项目 MyWeb 文件路径 C Inetpub wwwroo
  • JS 柯里化 (curry)

    用 JS 理解柯里化 函数式编程风格 xff0c 试图以函数作为参数传递 xff08 回调 xff09 和无副作用的返回函数 xff08 修改程序的状态 xff09 很多语言采用了这种编程风格 JavaScript xff0c Haskel
  • C语言头文件编程,C语言编程规范-头文件(Day2)

    1 头文件 背景 对于C语言来说 xff0c 头文件的设计体现了大部分的系统设计 不合理的头文件布局是编译时间过长的根本原因 xff0c 不合理的头文件实际上是不合理的设计 术语定义 依赖 xff1a 本章节特指编译依赖 若x h包含y h