首页 > 解决方案 > 具有多个文件(头文件)的 C 项目

问题描述

我对 C 语言相当陌生,但已经获得了一些经验。现在我正在使用(或多或少)复杂的数据结构(例如 Map(我将使用 Maps 作为示例))创建更大的项目。因为我希望我的数据结构代码可以在未来的项目中重复使用,所以我喜欢它们相当通用并且在单独的文件中。
由于C不使用/没有泛型(如Java)或模板(如C++)或任何类似的概念,我考虑过使用全局定义的数据类型,如

typedef union {
    int integer;
    char * str;
    // etc.
} data_t;

并将其放入main.h将包含在所有其他(头)文件中的文件中(可能使用警卫)。这对我来说效果很好,但是……</p>

有没有办法将数据结构集成到我的data_t(包括main.h使用data_t)中?
简单但显然不起作用(由于循环包含)的解决方案是#include "map.h"inmain.h同时还包括main.hin map.h; 如前所述,由于明显的原因,这不起作用。
基本上我想要一个可以容纳其他地图的地图,同时只使用一个data_t和一个地图实现。跟踪我所在的“层”将在周围的程序中完成(或者我可以在data_t其类型中添加一些信息,这不是这里的重点)。我知道仅使用void *;这将是可能的 但我不希望对原始数据类型进行不必要的引用,int如果我不需要的话。

有什么干净的方法来做这种行为吗?

谢谢 !
(如果需要任何实际代码,请告诉我)

实际代码

main.h我想包含像我这样的一般声明data_t

#ifndef _MAIN_H_
#define _MAIN_H_

#include "map.h"

typedef union {
    int integer;
    char * str;
    map_t map;
} data_t;

#endif

map.h

#ifndef _MAP_H_
#define _MAP_H_

#include "main.h"

typedef char * key_t;

typedef struct {
    int (*hash_f)(key_t);
    int size;
    data_t * data;
} map_t;

int map_init(map_t * map, int (*hash_f)(key_t key));
int map_put(map_t map, key_t key, data_t data);
int map_get(map_t map, key_t key);

#endif

编译make

% make
gcc -Wall -Wextra -Wpedantic -g -c main.c -o build/main.o
In file included from main.c:1:
./main.h:8:5: error: unknown type name 'map_t'
    map_t map;
    ^
1 error generated.
make: *** [build/main.o] Error 1

标签: cprojectheader-files

解决方案


让您的声明和类型定义在一个源代码文件中工作。
当它编译时,想想在标题中放什么。这样,您可以确保首先看到编译器对您的标头包含的一个(每个)代码文件所看到的内容。

如果你不能让它在一个不包含的代码文件中工作,那么你就会遇到一个无法用 headers 和 guards 解决的问题。
但是,如果您可以做到,那么只需查看单个文件并思考“现在我还想在下一个代码文件中使用什么?” 并将其放入标题中。(当然要确保只将声明、类型定义、宏定义移动到标题中。代码、变量定义不进入标题。)

循环依赖不能由守卫解决,只能通过(间接)多重包含而重新定义。


推荐阅读