übersicht - programmieren funktionen




Warum kann ein in einer Funktion deklarierter Unionstyp in einer anderen Funktion nicht verwendet werden? (2)

Das Beispiel versucht, den Absatz vorab zu veranschaulichen 1 (Hervorhebung meines):

6.5.2.3 ¶6

Eine besondere Garantie gilt, um die Verwendung von Vereinigungen zu vereinfachen: Wenn eine Vereinigung mehrere Strukturen enthält, die eine gemeinsame Anfangssequenz haben (siehe unten), und wenn das Vereinigungsobjekt derzeit eine dieser Strukturen enthält, ist es zulässig, die Vereinigung zu inspizieren anfänglicher Teil von ihnen irgendwo, dass eine Erklärung des vollständigen Typs der Vereinigung sichtbar ist . Zwei Strukturen teilen sich eine gemeinsame Anfangssequenz, wenn entsprechende Mitglieder kompatible Typen (und bei Bitfeldern die gleichen Breiten) für eine Sequenz aus einem oder mehreren Anfangsmitgliedern haben.

Da f vor g deklariert ist und außerdem der unbenannte Union-Typ local für g , gibt es keine Frage, ob der Union-Typ in f nicht sichtbar ist.

Das Beispiel zeigt nicht, wie u initialisiert wird. Unter der Annahme, dass das zuletzt in member geschriebene u.s2.m ist, u.s2.m die Funktion ein undefiniertes Verhalten auf, da p1->m ohne dass die übliche Anfangssequenzgarantie wirksam ist.

Das Gleiche gilt für den umgekehrten Fall, wenn u.s1.m zuletzt vor dem Funktionsaufruf geschrieben wurde und der Zugriff auf p2->m ein nicht definiertes Verhalten ist.

Beachten Sie, dass f selbst nicht ungültig ist. Es ist eine absolut sinnvolle Funktionsdefinition. Das undefinierte Verhalten rührt von der Übergabe in die Argumente &u.s1 und &u.s2 . Das ist es, was undefiniertes Verhalten verursacht.

1 - Ich zitiere n1570 , den C11-Standardentwurf. Die Spezifikation sollte jedoch die gleiche sein und nur ein oder zwei Absätze nach oben / unten verschoben werden.

Als ich ISO / IEC 9899: 1999 las (siehe: 6.5.2.3), sah ich ein Beispiel wie dieses (Hervorhebung meines):

Folgendes ist kein gültiges Fragment (da der Union-Typ in Funktion f nicht sichtbar ist ):

struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 * p1, struct t2 * p2)
{
      if (p1->m < 0)
            p2->m = -p2->m;
      return p1->m;
}
int g()
{
      union {
            struct t1 s1;
            struct t2 s2;
      } u;
      /* ... */
      return f(&u.s1, &u.s2);
}

Beim Testen habe ich keine Fehler und Warnungen gefunden.

Meine Frage ist: Warum ist dieses Fragment ungültig?


Eine der Hauptaufgaben der Common Initial Sequence-Regel besteht darin, Funktionen zu ermöglichen, mit vielen ähnlichen Strukturen austauschbar zu arbeiten. Das Erfordernis, dass Compiler annehmen, dass jede Funktion, die auf eine Struktur einwirkt, das entsprechende Member in einer anderen Struktur ändern kann, die eine gemeinsame Anfangssequenz hat, hätte jedoch nützliche Optimierungen zur Folge.

Obwohl der meiste Code, der auf der Common Initial Sequence basiert, garantiert, verwendet er einige leicht erkennbare Muster, z

struct genericFoo {int size; short mode; };
struct fancyFoo {int size; short mode, biz, boz, baz; };
struct bigFoo {int size; short mode; char payload[5000]; };

union anyKindOfFoo {struct genericFoo genericFoo;
  struct fancyFoo fancyFoo;
  struct bigFoo bigFoo;};

...
if (readSharedMemberOfGenericFoo( myUnion->genericFoo ))
  accessThingAsFancyFoo( myUnion->fancyFoo );
return readSharedMemberOfGenericFoo( myUnion->genericFoo );

Um die Verbindung zwischen Aufrufen von Funktionen, die auf verschiedene Gewerkschaftsmitglieder wirken, erneut zu betrachten, haben die Autoren des Standards angegeben, dass die Sichtbarkeit des Unionstyps innerhalb der aufgerufenen Funktion der entscheidende Faktor dafür sein sollte, ob Funktionen die Möglichkeit erkennen sollten, dass ein Zugriff auf den mode von z Ein FancyFoo kann sich auf den FancyFoo eines FancyFoo auswirken. Die Forderung nach einer Union, die alle Arten von Strukturen enthält, deren Adresse an readSharedMemberOfGeneric in derselben Kompilierungseinheit wie diese Funktion übergeben werden kann, macht die Common Initial Sequence-Regel weniger nützlich als sonst, würde aber zumindest einige Muster wie die oben verwendbar.

Die Autoren von gcc und clang waren der Ansicht, dass die Behandlung von Gewerkschaftsdeklarationen als Hinweis darauf, dass die beteiligten Typen an Konstrukten wie den oben genannten beteiligt sein könnten, jedoch ein unpraktisches Hindernis für die Optimierung darstellen würde Konstrukte auf andere Weise unterstützen sie einfach nicht. Folglich besteht die eigentliche Anforderung an Code, der die Common Initial Sequence-Garantien auf sinnvolle Weise ausnutzen muss, nicht darin, sicherzustellen, dass eine Union-Typdeklaration sichtbar ist, sondern sicherzustellen, dass clang und gcc mit dem -fno-strict-aliasing aufgerufen werden Flagge. Dazu gehört auch eine sichtbare Gewerkschaftserklärung, wenn das Praktikum nicht schaden würde, aber es ist weder notwendig noch ausreichend, um ein korrektes Verhalten von gcc und clang sicherzustellen.





unions