2

Is there a way to forward declare a function in a header file one that receives command struct defined in a different header file?

For example: I have the command_line structure defined in the command_line.h file:

typedef struct Command_Line 
{
    char *label;
    char *command_name;
    enum command_enum command_name_enum;
} Command_Line;

And I want to use the next function in a different header file, for example main.h:

int redefine_command(Command_Line *, char *, int);

I get an error that in main.h I use an undefined Command_Line is there a way to use it in a different header file? or must it all be in the same header file?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Have you included `command_line.h` in your `main.h` header file?? If you do, then are you including `main.h` inside of `command_line.h`? If you do that too, then you have a pretty standard circular inclusion problem, and you need to break it (like not including `main.h` inside `command_line.h`, directly or indirectly by another header file). – Some programmer dude Jul 24 '23 at 16:40
  • Related: https://stackoverflow.com/q/621356/509868 – anatolyg Jul 24 '23 at 16:51
  • 2
    I suspect it would be easy to answer if you show all of the relevant code; [mcve] – anatolyg Jul 24 '23 at 16:52
  • Guard your header files against multiple inclusion, then include them where needed. In this case, you need to include the structure definition in the header that declares the function. – Tom Karzes Jul 24 '23 at 16:57

2 Answers2

3

You can make a forward declaration of the struct Command_Line and define the function using the structure tag instead of the typedef:

/* declare the structure tag at global scope */
struct Command_Line;

/* declare the function prototype using the structure tag */
int redefine_command(struct Command_Line *, char *, int);

One good reason to use the same identifier for the structure tag and the typedef as you wisely chose to.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • @EricPostpischil: my bad, you are correct, this is such a counterintuitive scoping rule. Thankfully this scoping issue can be fixed. – chqrlie Jul 24 '23 at 21:48
1

One option is to have a header (call it header1.h) that defines (probably one of many other similar definitions):

typedef struct Command_Line Command_Line;

This specifies that there is a type struct Command_Line and an alias for it, Command_Line.

You can now modify the header that defines the structure type details like this:

#include "header1.h"

struct Command_Line
{
    char *label;
    char *command_name;
    enum command_enum command_name_enum;
};

You can also modify the header that declares the function to include header1.h:

#include "header1.h"

int redefine_command(Command_Line *, char *, int);

(I don't really like anonymous types in function signatures — I'd rather have the parameters named like int redefine_command(Command_Line *cmd, char *new_text, int options); so reading the declaration gives an indication of the meaning (compared with, say, int new_len). It's especially important when there are multiple arguments with the same type.)

From C11 onwards, you can repeat a typedef§6.7 Declarations):

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;

You might then avoid the separate header1.h header. However, the header1.h gives you an opaque type, which can be useful. You can pass pointers to the type between functions, but you can't access the data inside an opaque type because the compiler has no information about the internals of the type. (If it does have the information, it is no longer an opaque type.)

You can also do as chqrlie suggests and use struct Command_Line in the function declaration. The Linux kernel coding rules actually forbid the use of typedef for structure or union types. I think that typedef names have their uses.

Note that the structure tag is optional unless the structure contains pointers to values of its own type, hence:

/* Valid */
typedef struct
{
    char *label;
    char *command_name;
    enum command_enum command_name_enum;
} Command_Line;

This type can only be referenced via Command_Line (so the function would have to be declared and defined when the structure definition is visible).

The structure tag is needed in these examples:


/* Invalid - List *next does not refer to the List type being defined */
typedef struct
{
    void   *data;
    size_t  size;
    List   *next;
} List;

/* Valid */
typedef struct List
{
    void        *data;
    size_t       size;
    struct List *next;
} List;

/* Valid */
typedef struct List List;
struct List
{
    void   *data;
    size_t  size;
    List   *next;
};
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278