Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return an anonymous struct in C?

Trying some code, I realized that the following code compiles:

struct { int x, y; } foo(void) {
}

It seems as if we are defining a function named foo which returns an anonymous struct.

Does it only happen to compile with my compiler or is this legal C(99)?

If so, what is the correct syntax for a return statement and how can I correctly assign the returned value to a variable?

like image 399
Askaga Avatar asked Jan 09 '15 10:01

Askaga


People also ask

How do you return a struct in C?

Return struct from a function Here, the getInformation() function is called using s = getInformation(); statement. The function returns a structure of type struct student . The returned structure is displayed from the main() function. Notice that, the return type of getInformation() is also struct student .

Can you return a local struct in C?

One of them asked if you could return a struct from a function, to which I replied: "No! You'd return pointers to dynamically malloc ed struct s instead." I understand why struct b = a; should not work -- you cannot overload operator = for your data type.

What is anonymous structure in C?

Anonymous unions/structures are also known as unnamed unions/structures as they don't have names. Since there is no names, direct objects(or variables) of them are not created and we use them in nested structure or unions. Definition is just like that of a normal union just without a name or tag.

Should I return a struct or a pointer?

There are two ways of "returning a structure." You can return a copy of the data, or you can return a reference (pointer) to it. It's generally preferred to return (and pass around in general) a pointer, for a couple of reasons. First, copying a structure takes a lot more CPU time than copying a pointer.


4 Answers

The struct you're returning is not an anonymous struct. The C standard defines an anonymous struct as a member of another struct that doesn't use a tag. What you're returning is a struct without a tag, but since it isn't a member, it is not anonymous. GCC uses the name < anonymous > to indicate a struct without a tag.

Let's say you try to declare an identical struct in the function.

struct { int x, y; } foo( void )
{
    return ( struct { int x, y; } ){ 0 } ;
}

GCC complains about it: incompatible types when returning type 'struct < anonymous>', but 'struct <anonymous>' was expected.

Apparently the types are not compatible. Looking in the standard we see that:

6.2.7 Compatible type and composite type

1: Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.6 for declarators. 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; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; 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. For two structures or unions, corresponding bit-fields shall have the same widths. For two enumerations, corresponding members shall have the same values.

The second bold part, explains that if both struct are without the tag, such as in this example, they have to follow additional requirements listed following that part, which they do. But if you notice the first bold part, they have to be in separate translation units, and structs in the example aren't. So they are not compatible and the code is not valid.

It is impossible to make the code correct since if you declare a struct and use it in this function. You have to use a tag, which violates the rule that both have structs have to have the same tag:

struct t { int x, y; } ;

struct { int x, y; } foo( void )
{
    struct t var = { 0 } ;

    return var ;
}

Again GCC complains: incompatible types when returning type 'struct t' but 'struct <anonymous>' was expected

like image 119
2501 Avatar answered Nov 03 '22 15:11

2501


This works in my version of GCC, but seems like a total hack. It is perhaps useful in auto-generated code where you don't want to deal with the additional complexity of generating unique structure tags, but I'm sort of stretching to come up with even that rationalization.

struct { int x,y; }

foo(void) {
   typeof(foo()) ret;
   ret.x = 1;
   ret.y = 10;
   return ret;
}

main()
{
   typeof(foo()) A;

   A = foo();

   printf("%d %d\n", A.x, A.y);
}

Also, it's dependent on typeof() being present in the compiler -- GCC and LLVM seem to support it, but I'm sure many compilers do not.

like image 44
John Brennen Avatar answered Nov 03 '22 13:11

John Brennen


You probably cannot explicitly return some aggregate value from your function (unless you use a typeof extension to get the type of the result).

The moral of the story is that even if you can declare a function returning an anonymous struct, you should practically never do that.

Instead, name the struct and code:

struct twoints_st { int x; int y; };
struct twoints_st foo (void) {
   return ((struct twoints_st) {2, 3});
};

Notice that it is syntactically ok, but it is generally undefined behavior at execution to have a function without return (e.g., you could call exit inside it). But why would you want to code the following (probably legal)?

struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); }
like image 10
Basile Starynkevitch Avatar answered Nov 03 '22 14:11

Basile Starynkevitch


Here's a way to return anonymous structs in C++14 without any hacks I just discovered.
(C++ 11 should be sufficient, I suppose)
In my case a function intersect() returns std::pair<bool, Point> which is not very descriptive so I decided to make a custom type for the result.
I could have made a separate struct but it wasn't worth since I would need it only for this special case; that's why I used an anonymous struct.

auto intersect(...params...) {
    struct
    {
        Point point;
        bool intersects = false;
    } result;

    // do stuff...

    return result;
}

And now, instead of the ugly

if (intersection_result.first) {
    Point p = intersection_result.second

I can use the much better looking:

if (intersection_result.intersects) {
    Point p = intersection_result.point;
like image 3
Al.G. Avatar answered Nov 03 '22 15:11

Al.G.