我正在尝试清理一个 c 项目(使用 cmake),但我从根本上不理解如何组织我的 c 代码包含。
我有一个代码模块,其结构如下。这是一个非常精简的片段,但应该足以为这个问题提供必要的背景。
my_proj
|-- CMakeLists.txt
|-- main
|-- CMakieLists.txt
|-- main_app.c
common
|-- state
|-- CMakeLists.txt
|-- state
|-- state.h
|-- state.c
|-- state_sys
|-- state_sys.h
|-- state_sys.c
|-- state_data
|-- state_data.h
|-- state_data.c
|-- state_config
|-- state_config.h
|-- debug
|-- CMakeLists.txt
|-- debug
|-- debug.h
|-- debug.c
|-- error_codes
|-- error_codes.h
|-- error_codes.c
CMakeLists.txt 文件都很好。 Common 作为附加组件目录添加。它们使我能够成功构建该项目。然而,我已经开始尝试清理包含等内容,很快就发现我实际上并不了解它是如何工作的。之前行之有效的是一种混乱的分散枪方法——IU内心深处不明白它是如何或为什么行得通的。我对此并不满意。
问题:为什么以下不起作用?
**main_app.c**
#include "state.h"
#include "debug.h"
**debug.c**
#include "state.h"
#include "debug.h"
**debug.h**
#include "error_codes.h
**error_codes.c**
#include "error_codes.h"
**error_codes.h**
#include <stdio.h>
#include <string.h>
**state.h**
#include "state_config.h"
#include "state_sys.h"
#include "state_data.h"
#include "debug.h"
**state.c**
#include "state.h"
**state_sys.h**
#include "state_config.h"
**state_sys.c**
#include "state_sys.h"
**state_data.h**
#include "state_config.h"
**state_data.c**
#include "state_data.h"
**state_config.h**
#include "state_config.h"
#include "state_sys.h"
#include "state_data.h"
#include "debug.h"
/* Std Components */
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
抱歉,我想不出更好的方式来呈现此信息。基本上,我希望能够使用单个#include“state.h”将状态模块包含到其他代码模块中。调试模块也是如此。在状态模块内部,我已按功能将代码划分为漂亮整洁的块:sys、data 和 config(一种用于粘贴宏和系统级定义的顶级文件)。
我的想法是,使用这种策略,状态中的每个文件都将通过其头文件中的 state_config.h 包含状态中所有其他文件的内容。这意味着我也只需在一个位置添加 std c 包含即可。
可以从两个不同的层面来看待这个问题。首先为什么这不起作用?这似乎是 stackoverflow 的偏好。为此我想指出以下几点:
当我尝试编译它时,我看到如下错误:
/state_data.h:47:5: error: unknown type name 'bool'
/state_data.h:124:5: error: unknown type name 'uint32_t'
这是我没想到的。如果编译器递归地替换 .h 包含的内容,我希望通过 #include "state_config.h" 行引入 std 库。
然而,更有趣的问题是这应该如何运作。我的意思是将其修复到可以编译的程度并不是我的目标。我想了解 c include 应该如何在大型项目中构建。这比为什么我的一个文件找不到 bool 类型的前向声明有趣一百万倍。
您应该在源文件中建立层次结构:哪些文件是最基本的,哪些文件是最专业的。
#include
的关系应该是:专业文件包含基本文件,绝不相反!
最糟糕的情况是循环
#include
- 它默默地不起作用(编译器不会检测到它),效果看起来是随机且违反直觉的,并且只有当你的代码层次结构缺失时它才会开始发生。
您可以使用前向声明来减少头文件之间的依赖关系。这样,您就不需要经常使用
#include
。但更重要的是,您应该有一个心理模型,根据其目的,哪个文件可以包含哪些文件。