【问题标题】:How can I resolve this mutual dependency between header files?如何解决头文件之间的这种相互依赖关系?
【发布时间】:2019-05-04 00:31:05
【问题描述】:

请注意,关于 SO 的循环依赖有几个问题(包括我自己问过的一个),但我觉得没有一个问题能帮助我解决这个特殊问题。

请考虑以下两个文件:

table.h

#ifndef s_table_h
#define s_table_h

#include "value.h"
#include "object.h"

typedef struct {
    ObjectString* key;
    Value value;
} Entry;

typedef struct {
    int capacity;
    int count;
    Entry* entries;
} Table;

void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);

#endif

object.h

#ifndef s_object_h
#define s_object_h

#include "common.h"
#include "table.h"

typedef enum {
    OBJECT_STRING
} ObjectType;

typedef struct {
    ObjectType type;
    Table attributes;
} Object;

typedef struct {
    Object base;
    char* chars;
    int length;
} ObjectString;

bool stringsEqual(ObjectString* a, ObjectString* b);

#endif

如您所见,这两者相互依赖:table.h 需要ObjectString*,而object.h 需要具体的Table。两个对应的.c 实现文件分别访问ObjectString*Table 的具体成员。

解决此问题的推荐方法是什么?通常,在 C 中解决这类问题的常用方法是什么?

请仅解决技术方面的问题,而不是软件设计方面的问题。

【问题讨论】:

  • table.h 不需要objectstring 它只需要objectstring* 可以留待以后解决..

标签: c header circular-dependency


【解决方案1】:

我想您可能会争辩说我在这里解决了软件设计方面的问题,但如果不稍微重构您的代码,我不知道如何做到这一点。即,通过暂时避免 typedef。 (尽管我建议永久转储 typedef。)对于您的特定情况,table.h 不需要知道 ObjectString 是什么,因为它只使用指向它的指针。所以你可以简单地不在table.h中导入“object.h”,而是写:

object.h:

#ifndef s_object_h
#define s_object_h

#include "common.h"
#include "table.h"

typedef enum {
    OBJECT_STRING
} ObjectType;

typedef struct {
    ObjectType type;
    Table attributes;
} Object;

struct ObjectString {
    Object base;
    char* chars;
    int length;
};

typedef struct ObjectString ObjectString;

bool stringsEqual(ObjectString* a, ObjectString* b);

#endif

table.h:

#ifndef s_table_h
#define s_table_h

#include "value.h"

typedef struct {
    struct ObjectString* key;
    Value value;
} Entry;

typedef struct {
    int capacity;
    int count;
    Entry* entries;
} Table;

void initTable(Table* table);
void setTable(Table* table, struct ObjectString* key, Value value);
bool getTable(Table* table, struct ObjectString* key, Value* out);

#endif

【讨论】:

  • 感谢您的回答。一个问题:既然table.h 提到struct ObjectString* - 它如何编译?它没有 ObjectString 这个词的定义或声明。编译器不会抱怨吗?
  • 我尝试了您的解决方案 - 它有效!我忘记了即使table.c(实现文件)确实需要了解ObjectString 的详细信息——这并不意味着匹配的标头也需要。所以table.c 仍然包含object.h,但table.h 不包含。我的逻辑正确吗?
  • 编译器不会抱怨,因为即使它不知道 ObjectString 是什么,它也知道指向它的指针有多大,这就是它需要知道的全部内容。
  • 我明白了。另外,我想了解我最终采用的这种方法是否被认为是 C 中的良好实践:table.c 实现文件仍然需要包含整个object.h 标头(因为它取消引用指针),即使table.h 标头没有。标头和实现可以引用不同的依赖项吗?
  • 这是标准做法,#ifdef 的东西被称为“包含守卫”
【解决方案2】:

也许你可以这样做,将table.h和object.h放在一个名为both.h的文件中,不再需要table.h和object.h,只使用both.h:

#ifndef s_table_h
#define s_table_h

#include "value.h"
#include "common.h"

//#include "object.h"
//#include "table.h"


typedef struct A ObjectString;      // add

typedef struct {
    ObjectString* key;
    Value value;
} Entry;

typedef struct {
    int capacity;
    int count;
    Entry* entries;
} Table;





typedef enum {
    OBJECT_STRING
} ObjectType;

typedef struct {
    ObjectType type;
    Table attributes;
} Object;

typedef struct A {     // modify to typedef struct A
    Object base;
    char* chars;
    int length;
} ObjectString;

bool stringsEqual(ObjectString* a, ObjectString* b);
void initTable(Table* table);
void setTable(Table* table, ObjectString* key, Value value);
bool getTable(Table* table, ObjectString* key, Value* out);

#endif

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-16
    • 2010-11-12
    • 1970-01-01
    • 2015-04-22
    相关资源
    最近更新 更多