#include <stdio.h>
struct b; // not needed because:
struct a {
struct b * pb; // this member definition also forward declares struct b
int c;
};
typedef struct a a; // needed for a but not struct a because:
struct b {
struct a* pa; // this member definition also forward declares struct a
a * pa1;
void * c;
};
int main() {
printf("Hello, world!");
return 0;
}
Basically, you never need to forward declare struct b
on its own, because it always declares the partial type on the line itself when you use it to perform a pure declaration, so this is redundant code. The only benefit of this type of forward declaration is it can be used with a typedef. In C++, you don't need the typedef because struct and typedefs are in the same identifier namespace, so therefore struct b
becomes useful because it now declares b
, so you will see it in C++.
The whole point is if that type isn't completed before you use it to declare something that is actually a tentative definition and not a declaration (so struct e f
at file/block scope without extern
) that isn't a pointer, or if you attempt to dereference the pointer if it is a pointer, then you will get an incomplete type error.
So it's more like it allows you to use an incomplete type. Forget about forward declaration because this isn't a separate action. It's part of the line struct g* h
. You never need to use a forward declaration that something else actually requires (unless it's a typedef), because it has a forward declaration part of its own line.
Being able to use an incomplete type allows the type to be completed later on, before it is used. You typically see the benefits of forward declaration explained as not having to include the header containing the full definition in C++ when using a pointer to the type, only needing to do class bar
and then bar *
, or of course just using class bar*
without class bar
line, if this particular member is never used.
It doesn't let you use a type with incomplete size as a struct member either (if the size is unknown up to an including this like of code), even if the struct is never used to declare/define a variable. I think this is because the struct is a type, and when you provide the complete definition of a type, which you can only do once, it has to be of a complete size, not incomplete (having a member of unknown size), so the type would be unusable. This struct containing the incomplete struct never be referenced, whereas you can reference an incomplete type with incomplete size as opposed to a complete type with incomplete size (as long as you don't define anything with it), and you can reference, but not deference, (an address can be stored in) a pointer with incomplete type, because it has complete size. You can reference memory so long as its incomplete type doesn't entail an incomplete size. extern struct i j
at file/block scope is allowed because it will never be needed unless j
is referenced in the code, by which time the type must be complete.
context *whatever;
, does it? I thought sure it made you saystruct context *whatever;
... – Pucka