[...]
Hmm, I don't understand this.
If I have the following
typedef struct{
long x;
long y;
}AArdvark;
This says "There is a tagless (anonymous) struct type with
two elements, and `AArdvark' is an alias for that type." You
can now declare variables and pointers and such by using the
name `AArdvark' -- in fact, that's the only way you can declare
them, because there's no struct tag you could use.
struct{
char *cp1;
char *cp2;
}Whoami;
This says "There is a tagless struct type with two elements,
and `Whoami' is a variable of that type." Since the struct type
has no tag and there is no alias for it, there is no way you can
declare any more instances of it; `Whoami' is the one and only
instance of this type.
(Well, I suppose you could use malloc() to get a similarly-
sized piece of storage and then memcpy() to copy the content of
`Whoami' into it, but you couldn't actually do much with that
allocated storage until you copied it back into `Whoami' again.)
then I can do
AArdvark a;
a.y = 8;
AArdvark *ap = malloc(sizeof *ap);
ap -> y = 9;
but I can't do
struct Whoami wai;
struct Whoami *pwai = malloc(sizeof *pwai);
I get
error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type
Right. No `struct Whoami' has been declared. There's a
variable named `Whoami', and that variable is an instance of a
struct type, but there's no `struct Whoami'.
It is legal in C to mention a struct (or union) type without
declaring it; such a type is called "incomplete" until and unless
the details are filled in later. But until the details become
available, there are limitations on what you can do with such a
type: You can't make a variable of that type (because the compiler
doesn't know howbig it is), you can't apply `sizeof' to it (ditto)
you can't copy one instance to another by assignment (ditto), and
although you can form pointers to the type, you can't use them to
get at the unknown insides. This strange state of affairs actually
turns out to be useful when a library wants to use a type that is
"opaque" to the calling code. Much of <stdio.h> traffics in `FILE*'
pointers, but when you call fprintf() you neither know nor care
what's inside a `FILE'. (The example isn't perfect because there's
a strange technicality -- possibly a mistake -- in the C Standard
that forbids an incomplete `FILE', but the intent is the same.)
Nor can I do
struct Whoami.cp1 = "foo";
as I get
error: expected identifier or ‘(’ before ‘.’ token
There are two things wrong here. First, `struct Whoami' is
a type name, not a variable of that type: You can't assign a
value to a type, but only to an instance. Second, `struct Whoami'
is "incomplete" as described above, so the compiler has no idea
of what the type of it's `cp1' field might be, where it's positioned
inside the struct, nor even whether a `cp1' field exists!