C语言用好写好头文件
C语言用好写好头文件
特此说明: 内容主要参考魏永明老师老师的课程 C 语言最佳实践之头文件使用,也可以看下面我整理的笔记。建议初级C程序员多看,干货多水分少,质量很高。
1 说明背景
1)基本认识
- 头文件作用: 用于公用的函数、宏、数据类型或结构的声明和定义
- 头文件类型: 对外头文件、全局内部头文件、模块内部头文件、构建系统生成的头文件
2)遵循原则
- 最少包含原则
- 只包含必需的头文件
- 只包含被多个源文件共用的内容
- 自立原则
- 任意一个头文件放到源文件的第一行,都不会出现未定义或者未声明的编译错误
2 合理使用条件编译
CASE01: 防止头文件被重复包含
方法一:保卫宏
命名规则:<macro_name>
/* in src file */
#include "a/utils.h"
#include "b/utils.h"
/* in a/utils.h file */
#ifndef _FORBAR_A_UTILS
#define _FORBAR_A_UTILS
....
#endif /* not defined _FORBAR_A_UTILS */
/* in b/utils.h file */
#ifndef _FORBAR_B_UTILS
#define _FORBAR_B_UTILS
....
#endif /* not defined _FORBAR_B_UTILS */
方法二:pragma once
这个方法在C头文件比较少用
#pragma once
....
CASE02: 支持头文件被CPP源文件包含
/* in include/foobar.h file */
#include "foobar_macros.h"
FOOBAR_EXTERN_C_BEGIN
....
/* 外部函数和全局变量做特殊处理, 会生成符号信息 */
....
FOOBAR_EXTERN_C_END
/* in include/foobar_macros.h file */
#ifdef __cplusplus
#define FOOBAR_EXTERN_C_BEGIN extern "C" {
#define FOOBAR_EXTERN_C_END }
#else
#define FOOBAR_EXTERN_C_BEGIN
#define FOOBAR_EXTERN_C_END
#endif
3 了解CMAKE构建系统
CASE01: 编译时配置选项生成头文件
通过CMAKE构建系统配置CMakeLists.txt
,举例对于系统头文件,安装到系统:/usr/include/<product name>/XXX.h
# TODO: List the headers should be installed to system here.
set(FooBar_INSTALLED_HEADERS
"${FooBar_DERIVED_SOURCES_DIR}/foobar_version.h"
"${FooBar_DERIVED_SOURCES_DIR}/foobar_features.h"
"${FOOBAR_DIR}/include/foobar_macros.h"
"${FOOBAR_DIR}/include/foobar_errors.h"
"${FOOBAR_DIR}/include/foobar_utils.h"
"${FOOBAR_DIR}/include/foobar_ports.h"
"${FOOBAR_DIR}/include/foobar.h"
)
CASE02: 通过构建系统的宏替换功能
CMAKE利用宏替换模板文件foobar_features.h.in
中的指定内容,然后根据宏替换后的文件内容生成目标文件foobar_features.h
,该头文件作用到系统上
/* 模板文件 foobar_features.h.in , 此时 ENABLE_HTML 值为 ON */
#define _FOOBAR_ON 1
#define _FOOBAR_OFF 0
#define FOOBAR_ENABLE_HTML _FOOBAR_@ENABLE_HTML@
/* 目标文件 foobar_features.h */
#define _FOOBAR_ON 1
#define _FOOBAR_OFF 0
#define FOOBAR_ENABLE_HTML _FOOBAR_@ENABLE_HTML@
/* CMakeLists.txt定义转换规则 */
configure_file(include/foobar_features.h.in ${FooBar_DERIVED_SOURCES_DIR}/foobar_features.h)
3 抽象设计: 隐藏细节,统一接口
/* 模块内部使用头文件: 对隐藏的数据类型和接口的细节,放在context.h */
/* 对外提供的头文件: 抽象的接口等资源,安装到系统 */
4 参考资料
- best-practices-of-c
- C 语言最佳实践之头文件使用