[on forward declarations of variables via tentative definitions]
I suppose the reason I never remember this sort of two-step process is
because I'm never had a situation where it was useful. I don't find
the OP's header file example convincing.
Forward declarations of variables are required for the same
reason forward declarations of functions are required: sometimes
it is impossible to topological-sort-away the dependencies.
Suppose we have function f() that calls function g(), and function
g() that calls function f(). This order:
/* optional: static */
F_TYPE f(args) {
That's not a prototype - it is an incomplete definition only. Right,
it works lika a prototype for references after this point. A complete
definition would contain the type(s) of the parameters, each following
with the name of the formal parameter, e.g:
P_TYPE f(char *args) {
You've no prototype for this function in scope yet. So the copiler
knows nothing about it, so it complains.
...
}
/* optional: static */
G_TYPE g(args) {
...
f();
...
}
Declare prototypes of functions you have to use at least immediately
before you have to use them.
A prototype looks like a definition but without the definition (the
body of the fuction itself, e.g.
G_TYPE f(char *); /* declaration of typelist the fuction accepts
*/
/* and declaration of the value the function
returns */
or
G_TYPE f(char *args); /* name of formal parameter is optional, */
/* but nice for documentation */
As you declared later you needs the same for data. Make simply a
forward declaration, e.g.
struct mystruct; /* declares that somewhere later a struct mystruct
will occure */
/* so you can define a pointer to a struct
mystruct then */
struct mystruct *; /* you can anywhere make a forward declaration
like this */
/* even as nothing about the struct is known
yet. But */
/* it's fine to have a pointer to struct
mystruct before */
/* you needs the knowledge of the layout of
the struct */
You may even declare types:
typedef struct mystruct { /* declares an struct mystruct and saying
make an alias from it */
/* struct members */
} MYSTRUCT, *PMYSTRUCT; /* defining an alias for struct mystruct */
/* and struct mystruct *, an alias for a */
/* pointer to such a struct */
Using forward declaration for typedef:
typedef struct mystruct *PMYSTRUCT; /* an alias for an pointer type to
this struct */
typedef struct mystruct MYSTRUCT; /* an alias for a struct mystruct
*/
struct mystruct { /* declaring the struct mystruct
*/
/* members of the struct */
};
with all above:
struct mystruct { /* define a struct mystruct */
/* members of this struct */
} mystruct;
----
MYSTRUCT mystruct; /* define a struct mystruct */
MYSTRUCT *pmystruct; /* define a pointer to struct mystruct */
----
PMYSTRUCT pmystruct; /* define a pointer to struct mystruct */
with the knowledge above crossreference pointers */
typedef struct mystruct *PMYSTRUCT; /* pointer to an incomplete
struct */
/* declare a type, a pointer type (aliases) and the struct mystruct at
once */
typedef struct myotherstruct {
PMYSTRUCT p;
struct myotherstruct pme; /* there is no typedef for */
/* struct myotherstruct known yet */
/* as struct myotherstruct is not */
/* declared finally we can declare */
/* pinters to incomplete type */
/* only in this way */
/* more members ... */
} MYOTHERSTRUCT, *PMYOTHERSTRUCT;
/* d
typedef struct mystruct {
PMYOTHERSTRUCT p;
PMYSTRUCT pme; /* as we alredy knoe a type (an alias) */
/* of this struct we can use the alias
*/
/* to crate a pointer to this type
*/
/* more members .... */
] MYSTRUCT; /* pointer type is already declared above */