Viridya
Viridya

Reputation: 640

Cross include in C

I am currently experiencing a problem that I can solve easily, but I know there is another way to solve it so I am asking you help to figure it out :)

It's a classical problem: I have a 2 struct that need each others. To be more specific, here is the code:

a.h

#ifndef __A__
#define __A__
#include "b.h"

typedef struct {
    ... // there is no B
} A;

void A_func(A, B);
#endif

b.h

#ifndef __B__
#define __B__
#include "a.h"

typedef struct {
    ... //there is no A
} B;

void func_B(B, A);
#endif B

In my case, gcc is shouting me unknown type A in b.c I can manage that using another file containing the functions that use A and B, but I do not really want to...

Do you know a way to solve this?

Upvotes: 2

Views: 2481

Answers (2)

chqrlie
chqrlie

Reputation: 145287

You should use struct tags instead of just defining unnamed struct typedefs.

Here is a simple fix for your case:

a.h

#ifndef __A__
#define __A__

struct B;  // forward declaration

typedef struct A {
    ... // there is no B
} A;

void A_func(struct A, struct B);
#endif  /* __A__ */

b.h

#ifndef __B__
#define __B__

struct A;  // forward declaration

typedef struct B {
    ... //there is no A
} B;

void func_B(struct B, struct A);
#endif /* __B__ */

Upvotes: 1

There are two steps to resolve this.

1) Avoid the typedef. They don't provide a useful abstraction here, only syntactic sugar. And it comes at the price of being able to write correct code, as the next point demonstrates.

2) Even for passing structures by value, a function prototype requires no more than a forward declaration. The full structure definition is required only at the function definition, and calling code site.

With that in mind:

//a.h
#ifndef __A__
#define __A__

struct A{
... // there is no B
};

struct B; // Forward declaration

void A_func(struct A, struct B);

#endif



//b.h
#ifndef __B__
#define __B__

struct B{
... //there is no A
};

struct A; // Forward declaration

void func_B(struct B, struct A);

#endif

So yes, you must type struct A to refer to the type, but it conveys a lot of information! A reader of your code will know it's a structure type, possibly very large. They will be more likely to use your API properly if that information isn't hidden away from them.

But note the beautiful thing: neither header requires the other anymore. The mutual dependency between them has been reduced to just knowing about the names in each other. A user of a.h need never include b.h if they don't use A_func.

Upvotes: 3

Related Questions