39

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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Askaga
  • 6,061
  • 5
  • 25
  • 49
  • Seems like it some hack of gcc.With C99 strict it is giving error http://ideone.com/665vM2 – Ankur Jan 09 '15 at 10:18
  • 4
    @Shan: The function definition syntax is still legal. It merely complains about the missing return statement (and my question asks how to do a correct return statement in this situation). – Askaga Jan 09 '15 at 10:21
  • There's no such thing as anonymous structs in C99. You can make _compound literals_ but they always have local scope. – Lundin Jan 09 '15 at 10:45
  • I think the wording in §6.7.2.1 ¶8 _The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit._ rules out being able to create a variable of the same type as the defined return value, and rules out being able to create a compound literal of the same type, and therefore means that you can't actually return a value of the defined type. Section §6.2.7 discusses compatibility across translation units, which is important, but §6.7.2.1 controls what happens within a TU. The code in the question is 'legal' but useless, IMO. – Jonathan Leffler Jul 11 '16 at 04:28

7 Answers7

27

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2501
  • 25,460
  • 4
  • 47
  • 87
  • Hmm, interesting I never read that part of the Standard before. "Two types have compatible type if their types are the same" seems like complete nonsense to me (and it might apply to this situation; who knows), but that is not what I wanted to comment on. Might I conclude that although the two types in your example are not compatible, they would **both** be compatible with a similar type defined in a different translation unit? And that therefore compatibility is not a transitive relation? – Marc van Leeuwen Jan 09 '15 at 13:54
  • @MarcvanLeeuwen Types must be the same, with a lot of exceptions though. Structs without tags would be compatible if defined in different translation units. – 2501 Jan 09 '15 at 13:59
18

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jack Brennen
  • 353
  • 1
  • 5
  • 3
    This technique may be more reasonable than you think. See how the D language has convenient syntax for it: [https://dpaste.dzfl.pl/c5880e348812](https://dpaste.dzfl.pl/c5880e348812) – Cauterite Jul 19 '16 at 20:52
  • 1
    For most use cases, you can use `decltype()` in MSVC as a replacement for `typeof()`. `decltype()` is actually part of the C++ 11 standard and thus usually not supported by a plain C compilers, yet MSVC is a C++ compiler, even when compiling plain C source code with it, unless you force it not to be one by appropriate parameters. – Mecki Feb 20 '19 at 13:50
  • I get *"new types may not be defined in a return type"* with g++, but perhaps in C may be different than C++ – Prokop Hapala Jan 26 '21 at 14:20
  • 1
    The `typeof` is going to be a part of upcoming C23 standard. – tstanisl Jul 17 '22 at 12:36
  • @Cauterite the link seems to be down( – Sun of A beach Jul 31 '23 at 14:41
10

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); }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
3

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;
Al.G.
  • 4,327
  • 6
  • 31
  • 56
2

You could define a structure in specification of the return argument. Moreover you can use compound literals introduced in C99 for brevity:

#include<stdio.h>

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

int main()
{
    struct foo res = foo();
    printf("%d %d\n", res.x, res.y);
}

prints:

1 2

The code compiles in pedantic mode for C99 with no warnings. Note that the tag name is the same as function. This works because namespaces for structs and global objects are separated. This way you minimize the chances for accidental conflict of names. You can use something like foo_result if you consider it more suitable.

tstanisl
  • 13,520
  • 2
  • 25
  • 40
1

This works up to the newest version of GCC. It is particularly useful for creating dynamic arrays with macros. For instance:

#define ARRAY_DECL(name, type) struct { int count; type *array; } name

Then you can make the array with realloc, etc. This is useful because then you can create a dynamic array with any type, and there is one way to make all of them. Otherwise, you would end up using a lot of void *'s and then writing functions to actually get the values back out with casts and such. You can shortcut all of this with macros; that is their beauty.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gophyr
  • 406
  • 2
  • 11
1

Or you could create infinite recursion:

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

Which I think is completely legal.

AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • How about returning a pointer to the struct type? On the first invocation, malloc some memory and store a pointer in a global void*. After that, simply return the global void*. I think if one did that one could actually use the type one declared. – supercat Mar 24 '16 at 22:39