0

The question seems to be a classic one, but I didn't find an answer:

I have two struct type written in C ------ struct type A and struct type B, and B use A while A use B at the same time.

In a.h:

#include "b.h"
struct B;
typedef struct A {
    void (*func)(struct B* b);
}A;

In b.h:

#include "a.h"
typedef struct B {
    A a;
}B;

though this will work, it has a consequence --- when using the function fun "func", if I pass a variable declared in the form:

B* someb;

not:

struct B* someb;

there will be a warning when compiling, saying incompatible pointer type. Is this normal? could I avoid this warning?

realjin
  • 1,485
  • 1
  • 19
  • 38

4 Answers4

2

From your a.h header file, simply remove the line #include "b.h". The forward declaration struct B; is all you need.

That change will fix the circular include dependency, and will make any code using these headers more sane.

Then, wherever you want to make use of the B struct, simply include b.h, and use it with or without the struct keyword.

Some code to illustrate : the a.h header file :

/* a.h */
struct B;

typedef struct A {
    void (*func)(struct B* b);
} A;

The b.h header file :

/* b.h */
#include "a.h"

typedef struct B {
    A a;
} B;

A file that uses these header files :

/* some_file.c */
#include "b.h"

void fun() {
    B someb;
    someb.a.func(&someb);
}

void fun2() {
    struct B someb;
    someb.a.func(&someb);
}

Both fun and fun2 are just fine (from the compiler point of view - func hasn't been initialized, so calling it will cause an issue at run time).

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • yeah, you are right! I miss the forward declaration. BTW, could you tell me how could I be clear of compiler's view of struct like you(i.e. these trival things about struct declaration)? what kind of material can I read? – realjin Feb 25 '12 at 11:07
  • 1
    @realjin : the compiler is happy when your code is syntactically correct. So, knowing the C syntax in detail helps a lot. While the C standard is the definitive resource, it's a bit difficult to read. But any good resource on C will teach you much already. – Sander De Dycker Feb 25 '12 at 16:46
2

Cyclic include dependencies are never a good idea.

The simplest way is to have forward declarations for the struct tag and the typedef in "a.h"

typedef struct A A;
typedef struct B B;
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
0

Function func as you declared it gets as input a pointer to a struct B object, so when calling the function you should do like this:

B* somePointer; //because of your typedef you can omit struct 
func(somePointer);

I omitted the part of allocation of memory you should also manage...

As SO question Compiler Warning: Initialization incompatible pointer type shows, you should pass a pointer to the function in order to make changes visible in the object, otherwise you are just passing a copy of struct B and every change you make will only last in the functions scope.

I believe that's the reason of the warning.

Community
  • 1
  • 1
Matteo
  • 7,924
  • 24
  • 84
  • 129
  • Just as I mentioned in the comments below the question, my program runs well, what I want to do is to **avoid the warning**. – realjin Feb 25 '12 at 09:57
  • @user816109 `incompatible pointer type` is a typical warning when you're messing up with pointers arguments that don't match with the predefined standard. My guess is that the reason of this warning is because of what I pointed out, you are free to accept this suggestion or not. – Matteo Feb 25 '12 at 10:03
  • sorry I made a typo --- that should be "B* someb;" and "struct B* someb;". I've corrected it just now. – realjin Feb 25 '12 at 11:09
  • @user816109 no problem!glad you found your answer – Matteo Feb 25 '12 at 11:30
0

The struct whatever { /* ... */ }; defines a new type.
That new type name is struct whatever.

You can define another name for the type with typedef either in the same statement that defines the type

typedef struct whatever { /* ... */ } newtypename;

or in a different statement

struct whatever { /* ... */ };
typedef struct whatever newtypename;

You can even define a struct type with no name and get a new name for it

typedef struct { /* ... */ } newtypenameforstructwithnotag;
pmg
  • 106,608
  • 13
  • 126
  • 198