Reputation: 137
I read all the other posts with no success yet (eg forward declaration of a struct in C?)
There are two header files with functions which reference structs from each others' headers. Forward declaration isn't working...surely because i'm still doing it incorrectly:) Thoughts?
foo.h:
typedef struct{
...
}foostruct;
extern foostruct fooStruct; //this struct used in foo.c and other c files
typedef struct barstruct; //attempt at forward declaration
void fooFctn(barstruct *barVar); //needs definition from bar.h
bar.h:
typedef struct{
...
}barstruct;
extern barstruct barStruct; //this struct used in bar.c and other c files
typedef struct foostruct; //attempt at forward declaration
void fooFctn(foostruct *fooVar); //needs definition from foo.h
The error is
error: useless storage class specifier in empty declaration [-Werror]
src/search.h:123:18: error: unknown type name 'foostruct'
Since these structs were typedef-d originally i also tried just "foostruct;" without the identifier which (of course) doesn't work, likewise declaring "typedef struct fooVar foostruct" generates a redefinition error.
Upvotes: 1
Views: 3180
Reputation:
Structures and tags
struct { ... };
is an anonymous structure. It is only useful with typedefs, and only when that typedef name is used and declared in that one file. In other words, it cannot be used with forward declarations.
However, struct X { ... };
is a structure of type struct X
. It can be used for forward declarations. Note that X
is just the tag name used to denote a specific structure type, not the actual type. The tag name is used to distinguish between other declared structure types. This confuses people sometimes, so an example might help. Note that all of the declared structure types are different:
/* Declare an anonymous structure. */
struct {
int n;
};
/* Another anonymous structure. It in different from the previous one. */
struct {
double d;
};
/* Declare a structure of type `struct bar'. */
struct bar {
int n;
};
/* Declare a structure of type `struct foo'. */
struct foo {
int n;
};
/* Declare a variable `var' of type `struct foo'. */
struct foo var;
/* Unless a typedef for the `foo' type exists, or a preprocessor macro is used to replace `foo' with an actual type, this is a compilation error. */
foo var2;
Note that if you attempt to declare two structures with the same tag name, it is an error.
typedefs
The form for a typedef is the same as for a variable declaration with no initializer:
typedef TYPE NAME;
For example:
typedef int Integer;
declares the Integer
type to be the same as int
. The same can be done with structures:
/* Typedef'd anonymous structure */
typedef struct {
int foo;
} fooBType;
/* Typedef'd `struct foostruct' structure */
typedef struct foostruct {
int foo;
} fooGType;
The difference between the two:
fooBType
in other files are not possible because the structure referenced by fooBType
is anonymousstruct foostruct
referenced by fooGType
are possible because the type is able to be referenced by the structure tag and the struct
keyword, as in struct foostruct
or typedef struct foostruct fooGType;
I hope this helps.
Upvotes: 1
Reputation: 755114
In your foo.h
, this code:
typedef struct barstruct;
is a degenerate typedef
that announces that struct barstruct
exists, but does not give an alternative name for it (hence the 'useless storage class specifier in empty declaration' warning/error). You need:
typedef struct barstruct barstruct;
Then the code will work properly in foo.h
. The corresponding change is needed in bar.h
for struct foostruct
.
However, that still leaves you with a problem. The type barstruct
declared in foo.h
is not identical to the type barstruct
declared in bar.h
(because one is a tagged structure and one is a tagless structure). There are several ways around this. In C11 (but not C99 or C89), you can repeat a typedef
if they're identical.
You would therefore have the two typedef
lines:
typedef struct barstruct barstruct;
typedef struct foostruct foostruct;
at the top of the headers, and then define in bar.h
:
struct barstruct { … };
and in foo.h
:
struct foostruct { … };
If compatibility with earlier versions of C is important, then you need to consider using struct barstruct
and struct foostruct
in the function declarations:
foo.h
typedef struct foostruct foostruct;
struct foostruct
{
…
};
extern foostruct fooStruct;
struct barstruct;
void fooFctn(struct barstruct *barVar);
and analogously for bar.h
. This will also work with C11, of course.
Upvotes: 4
Reputation: 341
Properly typedef your struct should resolve your problem.
typedef struct foostruct foostruct;
Upvotes: 2