titel - Wie man eine anonyme Struktur in C zurückgibt?




title tag wordpress (4)

Beim Versuch, Code zu schreiben, erkannte ich, dass der folgende Code kompiliert:

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

Es scheint, als ob wir eine Funktion namens foo die eine anonyme struct zurückgibt.

Nun, meine Frage ist: Ist es nur mit meinem Compiler kompilieren oder ist das legal C (99)? Wenn ja, wie lautet die richtige Syntax für eine return-Anweisung und wie kann ich den zurückgegebenen Wert korrekt einer Variablen zuweisen?


Die Struktur, die Sie zurückgeben, ist keine anonyme Struktur. C-Standard definiert eine anonyme Struktur als ein Mitglied einer anderen Struktur, die kein Tag verwendet. Was Sie zurückgeben, ist eine Struktur ohne ein Tag, aber da es kein Mitglied ist, ist es nicht anonym. Gcc verwendet den Namen <anonymous> , um eine Struktur ohne ein Tag anzugeben.

Nehmen wir an, Sie versuchen, eine identische Struktur in der Funktion zu deklarieren.

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

gcc beklagt sich darüber: Inkompatible Typen bei der Rückgabe des Typs 'struct <anonymous>' aber 'struct <anonyme>' wurden erwartet

Anscheinend sind die Typen nicht kompatibel. Im Standard sehen wir, dass:

6.2.7 Kompatibler Typ und zusammengesetzter Typ

1: Zwei Typen haben einen kompatiblen Typ, wenn ihre Typen gleich sind. Zusätzliche Regeln zur Bestimmung, ob zwei Typen kompatibel sind, werden in 6.7.2 für Typspezifikatoren, in 6.7.3 für Typqualifizierer und in 6.7.6 für Deklaratoren beschrieben. Darüber hinaus sind zwei Struktur-, Vereinigungs- oder Enumerationstypen, die in separaten Übersetzungseinheiten deklariert sind, kompatibel, wenn ihre Tags und Member die folgenden Anforderungen erfüllen: Wenn einer mit einem Tag deklariert ist, muss der andere mit demselben Tag deklariert werden. Wenn beide innerhalb ihrer jeweiligen Übersetzungseinheiten abgeschlossen sind, gelten die folgenden zusätzlichen Anforderungen : zwischen ihren Mitgliedern muss eine Eins-zu-eins-Korrespondenz bestehen, so dass jedes Paar entsprechender Mitglieder mit kompatiblen Typen deklariert wird; Wenn ein Mitglied des Paars mit einem Ausrichtungsspezifizierer deklariert ist, wird der andere mit einem entsprechenden Ausrichtungsspezifizierer deklariert. und wenn ein Mitglied des Paares mit einem Namen deklariert ist, wird das andere mit dem gleichen Namen deklariert. Bei zwei Bauwerken müssen die entsprechenden Bauteile in derselben Reihenfolge angegeben werden. Für zwei Strukturen oder Vereinigungen müssen entsprechende Bitfelder die gleiche Breite haben. Für zwei Aufzählungen müssen die entsprechenden Elemente die gleichen Werte haben.

Der zweite fettgedruckte Teil erklärt, dass, wenn beide Struct ohne das Tag sind, wie in diesem Beispiel, sie zusätzlichen Anforderungen folgen müssen, die nach diesem Teil aufgeführt sind, was sie tun. Wenn Sie jedoch den ersten fettgedruckten Teil bemerken, müssen sie sich in separaten Übersetzungseinheiten befinden, im Beispiel sind dies keine Strukturen. Sie sind also nicht kompatibel und der Code ist nicht gültig.

Es ist unmöglich, den Code korrekt zu machen, da Sie, wenn Sie eine Struktur deklarieren und sie in dieser Funktion verwenden, ein Tag verwenden müssen, das gegen die Regel verstößt, dass beide Strukturen dasselbe Tag haben müssen:

struct t { int x, y; } ;

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

return var ;
}

Erneut gcc beschwert sich: inkompatible Typen bei der Rückgabe des Typs 'struct t', aber 'struct <anonyme>' wurde erwartet


Dies funktioniert bis zur neuesten Version von GCC. Es ist besonders nützlich zum Erstellen dynamischer Arrays mit Makros. Zum Beispiel:

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

Dann können Sie das Array mit Realloc, usw. machen. Dies ist nützlich, weil Sie dann ein dynamisches Array mit einem beliebigen Typ erstellen können, und es gibt eine Möglichkeit, sie alle zu machen. Sonst würden Sie am Ende eine Menge von void * s verwenden und dann Funktionen schreiben, um die Werte tatsächlich mit Umwandlungen und dergleichen wieder herauszubekommen. Sie können all dies mit Makros abkürzen; das ist ihre Schönheit.


Hier ist eine Möglichkeit, anonyme Strukturen in C ++ 14 ohne irgendwelche Hacks, die ich gerade entdeckt habe, zurückzugeben.
(C ++ 11 sollte ausreichen, nehme ich an)
In meinem Fall gibt eine Funktion intersect() std::pair<bool, Point> was nicht sehr std::pair<bool, Point> ist. Daher entschied ich mich für einen benutzerdefinierten Typ für das Ergebnis.
Ich hätte eine separate struct aber es war nicht wert, da ich es nur für diesen speziellen Fall brauchen würde; Deshalb habe ich eine anonyme Struktur verwendet.

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

    // do stuff...

    return result;
}

Und jetzt, anstelle des Hässlichen

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

Ich kann das viel besser aussuchen:

if (intersection_result.intersects) {
    Point p = intersection_result.point;

Oder Sie könnten eine unendliche Rekursion erstellen:

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

Was ich für völlig legal halte.





return-type