Reputation: 1369
How do I call a function that takes an anonymous struct in C?
Such as this function
void func(struct { int x; } p)
{
printf("%i\n", p.x);
}
Upvotes: 4
Views: 1944
Reputation: 181104
When a function declaration that provides a prototype is in scope, the arguments to calls to that function must be have types compatible with those declared in the prototype, where "compatible" has a specific meaning defined by the standard:
Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are [not relevant to the case in question]. Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; [...] and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order. [...]
(C11, 6.2.7/1)
Being "the same type" in the sense meant by the standard is a matter of scope, and there is no way for a caller of your function to satisfy that because the scope of the structure declaration in a function parameter list is restricted to the function definition in which it appears, if any, or to the parameter list alone if it appears only in a prototype.
To call that function, then, you must somehow take advantage of the additional rules for type compatibility, which are applicable (only) if func()
is defined in a different translation unit than the caller. In that case, the easiest thing to do is probably to typdef
a compatible type in the caller's translation unit:
typedef struct { int i; } one_int;
You would then prototype the function like so in that TU:
void func(one_int p);
and you would call it with a parameter of type one_int
. For example,
one_int oi = { 1 };
func(oi);
Do note, however, that although the above prototype is compatible with the function definition given in the question as long as they appear in different translation units, the two cannot appear in the same translation unit, so you cannot follow the usual recommendation that each .c file #include
the header(s) declaring its functions.
Overall, it would be far better to lift the struct declaration out of the prototype, either with the help of a typedef
such as is demonstrated above, or by giving it a tag, either one of which provides for it to be referenced from code away from its definition.
Upvotes: 6
Reputation: 14157
As type of the anonymous struct is visible only within the body of func()
you could use it to call func()
recursively.
void func(struct { int x; } p)
{
printf("x=%d\n", p.x);
func(p);
}
The code compiles fine except a warning mentioned in other answers.
Thus it is theoretically possible to call a function with anonymous struct as parameter. The initial call is a challange. I do not think that that there any portable way of invoking an initial call. Probably doable by casting a pointer func()
to other type of function pointer that is binary-compatible for a given implementation.
void func(struct { int x; } p)
{
printf("x=%d\n", p.x);
if (p.x --> 0)
func(p);
}
int main() {
// call through a pointer to function with unspecified number of arguments.
void (*func_p)() = func;
struct almost_p { int x; } p = { 10 };
func_p(p);
return 0;
}
Ii worked perfectly on my machine but it's non-portable and likely could trigger UB due incompatibility of struct {...}
and struct almost_p
.
However, if the argument is a pointer to anonymous struct then the situation looks more promising.
void func(struct { int x; } *p);
One can make an initial call as func(NULL)
.
Within func
, the actual p
object can be constructed with calloc()
.
After that you can call it func()
recursively or store instance p
in a global variable of type void*
.
Example:
void func(struct { int x; } *p) {
if (!p) p = calloc(1, sizeof *p);
printf("x=%d\n", p->x);
if (p->x++ < 10)
func(p);
}
int main() {
func(NULL);
return 0;
}
It compiles fine and outputs:
x=0
x=1
x=2
x=3
x=4
x=5
x=6
x=7
x=8
x=9
x=10
Upvotes: 2
Reputation: 23226
Although useful for some applications, a bare naked anonymous struct cannot be passed as a function argument all by itself in C. It needs some help, eg either a typedef handle, or a as a member of a named struct.
anonymous struct by itself:
struct {
int x;
};
as a function argument results in the warning:
"expected ‘struct ’ but argument is of type ‘struct ’ void func(struct { int x; } p)"
(noted by @Eugene Sh)
Help with a Typedef:
typedef struct
{
int x;
}anon_s;
void func(anon_s *p)
{
printf("%i\n", p->x);
}
int main(void)
{
anon_s anon = {10};
func(&anon);
return 0;
}
Or, carried by a surrogate with either a name or typedefed:
struct anon{
// Anonymous struct
struct
{
int x;
};
};
Upvotes: 3
Reputation: 311068
For starters you have no anonymous structure. You have an unnamed structure. The notion anonymous structure has a specific semantic in C.
You can not call the function because the structure type even if it will be named is not visible outside the function block scope.
You need to declare the structure outside the function parameter list assigning to it a name or an alias using typedef.
Upvotes: 1
Reputation: 11377
If you compile your program with warnings enabled you will get a warning like
warning: anonymous struct declared inside parameter list will not be visible outside of this definition or declaration
void func(struct { int x; } p)
^~~~~~
Therefor you need to give the record a name and use this name in the function declaration, for instance
typedef struct {
int x;
} T;
void func(T p)
{
printf("%i\n", p.x);
}
Upvotes: 1