Very little in C is illegal, meaning you cannot do it. Rather, many things are not defined by the C standard, meaning that, if you do them, the C standard does not say what will happen. Structures with no named members are such a thing.
C 2018 6.7.2.1 8 says, in part:
If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined.
If you need something to serve as an “unknown type” and do not want to use void
, then you can declare a structure whose tag is known but whose contents are not, as with:
struct foo;
Then you can use pointers to such structures (for example, you can define a pointer struct foo *p;
), but the compiler will not know the size or contents of such structures, so it cannot help you allocate them, manage arrays of them, or otherwise use them other than by passing pointers around and asking external routines (which do know about the contents).
Normally, in operations between C routines in one module and C routines in another module:
- In one source module that did not know about the contents of the structure, you would use a pointer (
struct foo *
).
- Another source module (often a software library of some sort) would know about the contents of the structure. It would, inside its own source code, define the full structure with
struct foo { /* various things */ };
, and it would perform services on this structure for the first module.
- Between two such C modules, the rules of the C standard would define the behavior.
Since you are interfacing between C and Ada, the rules for those interactions must be provided by your C and Ada implementations.