Strange compiler warning C: warning: ‘struct’ declared inside parameter list
To understand why the compiler complains, you need to know two things about C "struct"s:
- they are created (as a declared, but not yet defined, type) as soon as you name them, so the very first occurrence of
struct lol
creates a declaration - they obey the same "declaration scope" rules as ordinary variables
(struct lol {
declares and then begins defining the structure, it's struct lol;
or struct lol *
or something else that does not have the open-brace that stops after the "declare" step.)
A struct type that is declared but not yet defined is an instance of what C calls an "incomplete type". You are allowed to use pointers to incomplete types, as long as you do not attempt to follow the pointer:
struct lol *global_p;
void f(void) {
use0(global_p); /* this is OK */
use1(*global_p); /* this is an error */
use2(global_p->field); /* and so is this */
}
You have to complete the type in order to "follow the pointer", in other words.
In any case, though, consider function declarations with ordinary int
parameters:
int imin2(int a, int b); /* returns a or b, whichever is smaller */
int isum2(int a, int b); /* returns a + b */
Variables named a
and b
here are declared inside the parentheses, but those declarations need to get out of the way so that the the next function declaration does not complain about them being re-declared.
The same thing happens with struct
tag-names:
void gronk(struct sttag *p);
The struct sttag
declares a structure, and then the declaration is swept away, just like the ones for a
and b
. But that creates a big problem: the tag is gone and now you can't name the structure type ever again! If you write:
struct sttag { int field1; char *field2; };
that defines a new and different struct sttag
, just like:
void somefunc(int x) { int y; ... }
int x, y;
defines a new and different x
and y
at the file-level scope, different from the ones in somefunc
.
Fortunately, if you declare (or even define) the struct before you write the function declaration, the prototype-level declaration "refers back" to the outer-scope declaration:
struct sttag;
void gronk(struct sttag *p);
Now both struct sttag
s are "the same" struct sttag
, so when you complete struct sttag
later, you're completing the one inside the prototype for gronk
too.
Re the question edit: it would certainly have been possible to define the action of struct, union, and enum tags differently, making them "bubble out" of prototypes to their enclosing scopes. That would make the issue go away. But it wasn't defined that way. Since it was the ANSI C89 committee that invented (or stole, really, from then-C++) prototypes, you can blame it on them. :-)
The compiler is warning you about a forward declaration of struct lol
. C allows you to do this:
struct lol; /* forward declaration, the size and members of
struct lol are unknown */
This is most used when defining self-referencing structs, but it is also useful when defining private structs that are never defined in the header. Because of this latter use case, it is allowed to declare functions that receive or return pointers to incomplete structs:
void foo(struct lol *x);
However, just using an undeclared struct in a function declaration, as you did, will be interpreted as a local incomplete declaration of struct lol
whose scope is constrainted to the function. This interpretation is mandated by the C standard, but it is not useful (there is no way to construct the struct lol
to pass to the function) and is almost certainly not what the programmer intended, so the compiler warns.