头文件设计要点:

1、 头文件注释

2、 guard define

3、 尽量不要在头文件中暴露数据结构

4、 要自包含,保证头文件独立编译和功能正确

5、 函数声明前加XXX_API利于拓展

6、 宏的定义

7、 对外提供的头文件放于指定的目录结构

1. 文件头注释

应该加在每个头文件的顶部,必须包含版权许可、功能说明、作者和创建日期。

例如:

a)   /*

b)   * Copyright (c) Huawei Technologies Co., Ltd. XXXX. All rights reserved.

c)   * Description: 文件功能描述

d)   * Author: 王二

e)   * Create: 2012-12-22

f)  */

2. guard define

整个头文件应该在guard define之间, 为防止头文件被多重包含,所有头文件都应当使用 #define 作为包含保护;

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

ü  保护符使用唯一名称;

ü  建议考虑项目源代码树顶层以下的文件路径 不要在受保护部分的前后放置代码或者注释,文件头注释除外。

假定 VOS 工程的 timer 模块的 timer.h,其目录为 vos/include/timer.h 。其保护符若使用 'TIME_H' 很容易不唯 一,所以使用项目源代码树的全路径,如:

如:

1)   #ifndef VOS_INCLUDE_TIMER_H

2)   #define VOS_INCLUDE_TIMER_H

3)    //声明对外的接口

4)    #endif

另外,如果这个头文件可能给c++使用,要加上

1)  #ifdef __cplusplus

2)  extern "C" {

3)  #endif

4)  //声明对外的接口

5)  #ifdef __cplusplus

6)  }

7)  #endif
注:禁止在 extern "C" 中包含头文件

3. 尽量不要在头文件中暴露数据结构

这样可以用户降低对你的实现的依赖,也减少了用户的编译时间

1)  typedef struct lua_State lua_State;

2)  LUA_API lua_State *lua_open (void);

3)  LUA_API void       lua_close (lua_State *L);

可以看到虽然用户会一直使用lua_State,但是并不知道lua_State的结构是什么

从一个使用lua的例子程序可以看出:

1)  #include "lua.h"

2)  #include "lauxlib.h"

3)  #include "lualib.h"

4)

5)  int main(int argc, char *argv[])

6)  {

7)      lua_State *L = lua_open();

8)      const char *buf = "var = 100";

9)      int var ;

10)    luaopen_base(L);

11)    luaopen_io(L);

12)    lua_dostring(L, buf);

13)    lua_getglobal(L, "var");

14)    var = lua_tonumber(L, -1);

15)    lua_close(L);

16)    return 0;

17)}

4. 要自包含,保证头文件独立编译和功能正确

i.     能独立编译

要保证本头文件在任何使用场景下,都能独立编译。其中,相对路径引入就是一个案例。如:

#include <comm_type.h>不是标准库情况下,可能无法引入相关文件,可改成:

#include “../../XXX/XXX/ comm_type.h”

ii.     对外提供功能正确

头文件能独立编译了,但不一定能对外提供的功能是正确的。对外提供的功能可能还需要代码适配,以保证功能正确。

5.  下面是一个私有宏暴露给模块外部,致使相关模块使用时能编译通过,但功能却不正确。

解决办法就是不要暴露数据本身,通过接口反馈给外部模块数据值即可。(这个问题,也是尽量不要在头文件中暴露数据结构的一个典型案例)

案例:

1)  功能失败点,从图1看到rsaM.Datalen = RSA_LEN,再从图2看到RSA_LEN != pData->dataLen的应该是相等,但实际结果却是错误的,这就是问题暴露点

图1

图2

2)  继续追查RSA_LEN,它是RSA_KEY_LEN的重定义,见图3。而从图4可以看出RSA_KEY_LEN的值由一个开关控制,编译环境不一样,值不同

图3

图4

3)  问题在于本模块对外提供能力时,没有考虑到编译环境的要求,应用方也没有明白这点,应用方无法掌控这个宏的编译环境,从而无法得到正确值引发了这个问题。解决办法就是通过接口对外提供值,而不是数据结构本身。

5. 函数声明前加XXX_API利于拓展

iii.      Lua的例子,如果定义了LUA_API就是给LUA内部使用的,如果没定义LUA_API就是for user的

下面是内部使用的例子:

1)  #ifndef LUA_API

2)  #define LUA_API

3)  #endif

4)

5)  LUA_API lua_State *lua_open (void);

下面是外部使用的例子:

6)  #ifndef LUA_H

7)  #define LUA_H

8)  #endif

9)

10)LUA_H lua_State *lua_close (void);

6. 宏的定义时,尽量使用括号来包住所定义的对象

i.     宏定义嵌入某个表达式使用,用括号将其包住。此方法如果用于语句环境将会出语法错误

1)  #define LUA_TNONE       (-1)

2)

3)  #define lua_register(L,n,f) \

4)         (lua_pushstring(L, n), \

5)          lua_pushcfunction(L, f), \

6)          lua_settable(L, LUA_GLOBALSINDEX))

ii.     宏定义当语句使用,用do while(0)将其包住。此方法如果用于表达式环境将会出语法错误

7)  #define DOSOMETHING () \

8)         do{

9)             foo1();

10)           foo2();

11)          }while(0)

7. 对外提供的头文件放于指定的目录结构

一般应该使用一个单独的include目录来包含要发布的头文件,但不应该把内部使用的头文件包含进去。例如:Lua的include目录只包含了三个头文件lauxlib.h , lua.h, lualib.h,很简洁

专业的C头文件设计和重构指南的更多相关文章

  1. c++ 私有函数 头文件设计

    clock.h #ifndef CLOCK_H_INCLUDED #define CLOCK_H_INCLUDED class Clock {public: static void HandleExd ...

  2. 让QT编译快一点(增加基础头文件)

    姚冬,中老年程序员 进藤光.杨个毛.欧阳修 等人赞同 我是来反对楼上某些答案的.我曾经用MFC写了金山词霸(大约20多万行),又用Qt写了YY语音(大约100多万行),算是对两种框架都比较有经验.纠正 ...

  3. ArcCore重构-头文件引用问题的初步解决

    基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5   基本问题 1. 头文件引用混乱,所有头文件通过从搜索路径(-I)中引用,存在名称污染问题,需加入路径信息:   ...

  4. C++ 头文件系列(array)

    注意,该头文件仅在C++11中标准才开始出现. 简介 与语言内置的数组一样, array类模版支持几乎所有内置数组包含的特性: 顺序的(sequence) 内存连续的(contiguous stora ...

  5. C++解析头文件-Qt自动生成信号声明

    目录 一.瞎白话 二.背景 三.思路分析 四.代码讲解 1.类图 2.内存结构声明 3.QtHeaderDescription 4.私有函数讲解 五.分析结果 六.下载 一.瞎白话 时间过的ZTMK, ...

  6. minix2.0内核组织结构与公用头文件说明

    Minix2.0操作系统的源代码由两个目录组成:include/目录和src/目录 include/目录包含了操作系统所有的头文件(即.h文件) src/目录下包含了操作系统所有的源文件(.c或.s文 ...

  7. Objective-C声明在头文件和实现文件中的区别

    Objective-C声明在头文件和实现文件中的区别 转自codecloud(有整理) 调试程序的时候,突然想到这个问题,百度一下发现有不少这方面的问答,粗略总结一下: 属性写在.h文件中和在.m文件 ...

  8. c++ 头文件包含问题-include&class

    http://blog.csdn.net/jiajia4336/article/details/8996254 前向声明概念(forward declaration) 在程序中引入了类类型的B.在声明 ...

  9. 基于WDF的PCI/PCIe接口卡Windows驱动程序(3)- 驱动程序代码(头文件)

    原文出处:http://www.cnblogs.com/jacklu/p/4679304.html 在WDF的PCIe驱动程序中,共有四个.h文件(Public.h  Driver.h  Device ...

  10. C/C++关于string.h头文件和string类

    学习C语言时,用字符串的函数例如stpcpy().strcat().strcmp()等,要包含头文件string.h 学习C++后,C++有字符串的标准类string,string类也有很多方法,用s ...

随机推荐

  1. 04_Linux基础-.&..-cat-tac-重定向-EOF-Shell-more-ps-less-head-tail-sed-grep-which-whereis-PATH-bash-usr-locate-find

    04_Linux基础-.&..-cat-tac->&>>-EOF-Shell-more-ps-less-head-tail-sed-grep-which-wherei ...

  2. [SDR] GNU Radio 系列教程(二) —— 绘制第一个信号分析流程图

    目录 1.前言 2.启动 GNU Radio 3.新增块 4.运行 本文视频 参考链接 1.前言 本文将介绍如何在 GNU Radio 中创建和运行第一个流程图. 2.启动 GNU Radio GNU ...

  3. KingbaseES V8R6兼容Oracle的exp-imp导出导入工具使用

    说明: KingbaseES V8R6版本中的兼容Oracle的exp-imp导入导出工具,支持完全模式.用户模式和表模式的导出功能. 本次案例数据库版本: test=# select version ...

  4. KingbaseES R3 受限dba影响集群切换

    ​ 一.受限dba功能说明(参考自官方文档) 受限DBA 受限DBA可以对当前DBA的权限进行一定限制.当功能开启后DBA将不能更改以下对象: Table Database Function(by n ...

  5. AOP实现系统告警

    工作群里的消息怕过于安静,又怕过于频繁 一.业务背景 在开发的过程中会遇到各种各样的开发问题,服务器宕机.网络抖动.代码本身的bug等等.针对代码的bug,我们可以提前预支,通过发送告警信息来警示我们 ...

  6. ProxySQL 匹配规则

    现实中很多场景要求更新数据能立马查到数据,而主从同步在这方面无解,所以从规则上修改,一些需要及时查询的语句在主上. # 用户登录 mysql -h192.168.0.103 -P16032 -urad ...

  7. Kibana: 运用Data Visualizer来分析CSV数据

  8. 关于Loki中promtail组件收集日志的几点思考

    promtail组件是采用docker方式运行的,配置文件也是在docker容器中,宿主机中没有挂载点,这就有问题了. 宿主机中没有挂载配置文件,也就没法修改,登录promtail的docker容器中 ...

  9. Prometheus自身的监控告警规则

    1.先在 Prometheus 主程序目录下创建rules目录,然后在该目录下创建 prometheus-test.yml文件,内容如下: 内容很多,可以根据实际情况进行调整. 规则参考网址:http ...

  10. MySQL数据库-数据表(上)

    数据表的基本操作. MySQL 数据库支持多种数据类型,大致可以分为 3 类:数值类型.日期和时间类型.字符串(字符)类型. (1)数值类型 数值类型用于存储数字型数据,这些类型包括整数类型(TINY ...