Circular (triangular) structure reference

T

T Koster

After a few years of programming C, I had come to believe that I finally
knew how to correctly organise my structure definitions in header files
for mutually dependent structures, but I find myself stumped again with
this little love triangle. Here is some background:

m_commands.h defines
- struct command_callbacks, which contains
- a struct conn * reference
- struct command, which contains
- a struct command_callback reference
- a struct conn * reference
- struct input, which contains
- a struct conn * reference
- a struct command * reference
m_net.h defines
- struct conn, which contains
- a struct command * reference

The header files are guarded against circular inclusion using the the
standard #ifndef MYHEADER/#define MYHEADER/#endif wrappings.

Now both header files include each other, as "struct conn" requires a
"struct input *" element, and each "struct input" element requires a
"struct conn *" element. So far this has not caused any problems thanks
to the circular loop guards. However, this time "struct command",
through the elements in the command_callbacks structure, contains
pointers to a function which takes a "struct conn *" parameter, and this
appears to be giving problems when m_net.h is included first.

For example:
main.c includes m_net.h
....which includes m_commands.h
....which doesn't re-include m_net.h due to the #defined include-guard
to stop the circular inclusion loop
m_commands.h 'tries' to define "struct command_callbacks" which contains
some function pointers with "struct conn *" parameters, but "struct
conn" is not defined until *after* m_commands.h has been included.

For those of you who use gcc, its warnings are as follows:
In file included from m_net.h:11,
from main.c:7:
m_commands.h:31: warning: `struct conn' declared inside parameter list
In file included from m_net.h:11,
from m_net.c:21:
m_commands.h:31: warning: `struct conn' declared inside parameter list


If all that was a bit cryptic, the problem parts of the header files in
question are included below for those who would understand the problem
better from reading the C:

<-------- m_commands.h -------->
#ifndef INC_COMMANDS_H
#define INC_COMMANDS_H

#include "m_net.h"

struct command_callbacks
{
int (*execute)(struct conn *, int, void **);
int (*abort)(struct conn *);
};

struct command
{
char * name;
int argc_expect;
int * argv_expect;
int flags;
struct command_callbacks callbacks;
};

struct input
{
struct command * cmd;
struct conn * caller;
int argc;
void ** argv;
};
#endif

<-------- m_net.h -------->
#ifndef INC_NET_H
#define INC_NET_H

#include "m_db.h" /* for Queue types -- irrelevant here */
#include "m_commands.h"

struct conn
{
struct conn * prev;
struct conn * next;

int fd;
char * address;

int phase;
int security;

char input_buf[MAX_INPUT_LINE_LENGTH];
char * input_buf_cursor;

Queue * input_queue;
Queue * output_queue;

struct input * last_input;
};
#endif

I hope that's all comprehensible. How would I go about fixing this?
The FAQ answers 1.14, 2.3 and 10.7 seem inadequate for this problem.

Thanks in advance,
Thomas
 
I

infobahn

T said:
After a few years of programming C, I had come to believe that I finally
knew how to correctly organise my structure definitions in header files
for mutually dependent structures, but I find myself stumped again with
this little love triangle. Here is some background:

m_commands.h defines
- struct command_callbacks, which contains
- a struct conn * reference
- struct command, which contains
- a struct command_callback reference
- a struct conn * reference
- struct input, which contains
- a struct conn * reference
- a struct command * reference

Add m_commands_meta.h:

#ifdef etc
struct command_callbacks;
struct command;
struct input;
#endif

Include this instead of m_commands.h, in your other headers.
etc etc ad nauseam
 
T

T Koster

infobahn said:
Add m_commands_meta.h:

#ifdef etc
struct command_callbacks;
struct command;
struct input;
#endif

Include this instead of m_commands.h, in your other headers.
etc etc ad nauseam

Thanks, that fixed it. I'll make such "_meta.h" header files for all
those like interfaces, and include those instead when only a bare-bones
structure tag declaration is required to satisfy the language, rather
than full knowledge of the structure definition.

Thomas
 
B

Ben Pfaff

infobahn said:
Add m_commands_meta.h:

#ifdef etc
struct command_callbacks;
struct command;
struct input;
#endif

Include this instead of m_commands.h, in your other headers.

It seems silly to me to add an entire header file for this, when
it is perfectly safe to write `struct command;', etc., in any
header file that needs it.
 
I

infobahn

Ben said:
It seems silly to me to add an entire header file for this, when
it is perfectly safe to write `struct command;', etc., in any
header file that needs it.

Depends on how volatile the names are.
 
B

Ben Pfaff

infobahn said:
Depends on how volatile the names are.

If you change the names, you will have to change the references
to them. As far as I can tell that's normally enough work that
an extra header won't help significantly.
 
I

infobahn

Ben said:
If you change the names, you will have to change the references
to them.

Yeah, I was thinking the same thing just after I pressed that button.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top