Aviv Cohn
Aviv Cohn

Reputation: 17243

How can I resolve this mutual dependency between header files?

Please note, there are several questions regarding circular dependencies on SO (including one I have asked myself), but I feel none of them has helped me with this particular problem.

Please consider the two following files:

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

As you can see, these two depend on each other: table.h needs ObjectString*, and object.h needs a concrete Table. Both corresponding .c implementation files access concrete members of the ObjectString* and Table respectively.

What is the recommended way to solve this problem? And generally, what would be the common approach to these kinds of problems in C?

Please address purely the technical aspect, and not the software-design one.

Upvotes: 0

Views: 496

Answers (2)

Tom
Tom

Reputation: 491

Maybe you can do like this,put table.h and object.h together to one file named both.h,no longer need table.h and object.h,only use 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

Upvotes: 0

William Pursell
William Pursell

Reputation: 212514

I suppose you could argue that I'm addressing the software-design aspect here, but I don't know how to do this without slightly refactoring your code. Namely, by avoiding the typedef temporarily. (Although I would advise dumping the typedef's permanently.) For your particular case, table.h doesn't need to know what ObjectString is, since it only uses a pointer to it. So you can simply not import "object.h" in table.h, and instead write:

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

Upvotes: 2

Related Questions