Unterschied zwischen einer Struktur und einer Union

Lesezeit: 9 Minuten

Benutzeravatar von gagneet
gagneet

Gibt es ein gutes Beispiel, um den Unterschied zwischen a struct und ein union? Im Grunde kenne ich das struct verwendet den gesamten Speicher seines Mitglieds und union verwendet den größten Mitgliederspeicherplatz. Gibt es noch andere Unterschiede auf der Betriebssystemebene?

Benutzeravatar von Kyle Cronin
Kyle Cronin

Bei einer Vereinigung soll nur eines der Elemente verwendet werden, da sie alle an derselben Stelle gespeichert sind. Dies macht es nützlich, wenn Sie etwas speichern möchten, das einer von mehreren Typen sein könnte. Eine Struktur hingegen hat einen separaten Speicherort für jedes ihrer Elemente und sie können alle gleichzeitig verwendet werden.

Um ein konkretes Beispiel für ihre Verwendung zu geben: Ich habe vor einiger Zeit an einem Scheme-Interpreter gearbeitet und im Wesentlichen die Scheme-Datentypen auf die C-Datentypen gelegt. Dies beinhaltete das Speichern einer Aufzählung in einer Struktur, die den Typ des Werts angibt, und eine Union zum Speichern dieses Werts.

union foo {
  int a;   // can't use both a and b at once
  char b;
} foo;

struct bar {
  int a;   // can use both a and b simultaneously
  char b;
} bar;

union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!

struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK

bearbeiten: Wenn Sie sich fragen, welche Einstellung xb auf ‘c’ den Wert von xa ändert, ist es technisch gesehen undefiniert. Auf den meisten modernen Maschinen ist ein Zeichen 1 Byte und ein Int 4 Bytes. Wenn Sie also xb den Wert ‘c’ geben, erhält das erste Byte von xa denselben Wert:

union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

Drucke

99, 99

Warum sind die beiden Werte gleich? Da die letzten 3 Bytes von int 3 alle Null sind, wird es auch als 99 gelesen. Wenn wir eine größere Zahl für xa eingeben, werden Sie sehen, dass dies nicht immer der Fall ist:

union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

Drucke

387427, 99

Um einen genaueren Blick auf die tatsächlichen Speicherwerte zu werfen, lassen Sie uns die Werte in Hex einstellen und ausdrucken:

union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);

Drucke

deadbe22, 22

Sie können deutlich sehen, wo die 0x22 die 0xEF überschrieben hat.

ABER

In C ist die Reihenfolge der Bytes in einem int nicht definiert. Dieses Programm hat auf meinem Mac 0xEF mit 0x22 überschrieben, aber es gibt andere Plattformen, auf denen es stattdessen 0xDE überschreiben würde, weil die Reihenfolge der Bytes, aus denen das int besteht, umgekehrt wurde. Daher sollten Sie sich beim Schreiben eines Programms niemals auf das Verhalten des Überschreibens bestimmter Daten in einer Union verlassen, da diese nicht portierbar sind.

Weitere Informationen zur Anordnung von Bytes finden Sie unter Endianität.

  • Verwenden Sie dieses Beispiel in Union, wenn xb=’c’, was wird in xa gespeichert? ist es die Referenznummer des Zeichens?

    – kylex

    6. Dezember 2008 um 19:04 Uhr

  • hoffentlich erklärt das ausführlicher, was in xa gespeichert wird, wenn Sie xb setzen

    – Kyle Cronin

    6. Dezember 2008 um 19:33 Uhr

  • @KyleCronin Ich glaube, ich verstehe es. In Ihrem Fall haben Sie eine Gruppe von Typen, von denen Sie wissen, dass Sie nur einen verwenden müssen, aber Sie wissen bis zur Laufzeit nicht, welchen – die Union ermöglicht Ihnen dies. Vielen Dank

    – Benutzer12345613

    21. Februar 2012 um 0:49 Uhr

  • @ user12345613 Unions können als eine Art Basisklasse für Strukturen verwendet werden. Sie können eine OO-Hierarchie mit Vereinigungen von Strukturen emulieren

    – Morten Jensen

    12. März 2013 um 21:57 Uhr

  • @Lazar Byte-Reihenfolge in Multibyte-Typen hängt von Endianness ab. Ich schlage vor, den Wikipedia-Artikel darüber zu lesen.

    – Kyle Cronin

    27. April 2016 um 18:11 Uhr

Hier ist die kurze Antwort: Eine Struktur ist eine Datensatzstruktur: Jedes Element in der Struktur weist neuen Speicherplatz zu. Also eine Struktur wie

struct foobarbazquux_t {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

mindestens zuweist (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) Bytes im Speicher für jede Instanz. (“Mindestens”, weil Einschränkungen der Architekturausrichtung den Compiler zwingen können, die Struktur aufzufüllen.)

Auf der anderen Seite,

union foobarbazquux_u {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

weist einen Speicherblock zu und gibt ihm vier Aliase. So sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double))wieder mit der Möglichkeit einer Ergänzung für Ausrichtungen.

Benutzeravatar von cygil
Cygil

Gibt es ein gutes Beispiel, um den Unterschied zwischen einer ‘Struct’ und einer ‘Union’ zu erklären?

Ein imaginäres Kommunikationsprotokoll

struct packetheader {
   int sourceaddress;
   int destaddress;
   int messagetype;
   union request {
       char fourcc[4];
       int requestnumber;
   };
};

In diesem imaginären Protokoll wurde festgelegt, dass basierend auf dem “Nachrichtentyp” die folgende Stelle im Header entweder eine Anforderungsnummer oder ein vierstelliger Code ist, aber nicht beides. Kurz gesagt, Vereinigungen ermöglichen es, dass derselbe Speicherort mehr als einen Datentyp darstellt, wobei garantiert ist, dass Sie jeweils nur einen der Datentypen speichern möchten.

Unions sind größtenteils ein Low-Level-Detail, das auf dem Erbe von C als Systemprogrammiersprache basiert, wo “überlappende” Speicherorte manchmal auf diese Weise verwendet werden. Sie können manchmal Vereinigungen verwenden, um Speicher zu sparen, wenn Sie eine Datenstruktur haben, in der nur einer von mehreren Typen gleichzeitig gespeichert wird.

Im Allgemeinen kümmert sich das Betriebssystem nicht um Strukturen und Vereinigungen oder kennt sie nicht – sie sind beide einfach Speicherblöcke für es. Eine Struktur ist ein Speicherblock, der mehrere Datenobjekte speichert, wobei sich diese Objekte nicht überschneiden. Eine Vereinigung ist ein Speicherblock, der mehrere Datenobjekte speichert, aber nur Speicher für das größte davon hat und daher nur eines der Datenobjekte gleichzeitig speichern kann.

  • Angenommen, Sie haben eine packetheader ph; Wie greifen Sie auf die Anfragenummer zu? ph.request.requestnumber ?

    – justin.m.chase

    25. August 2015 um 2:14 Uhr

Johannes Schaub - Benutzerbild der litb
Johannes Schaub – litb

Wie Sie bereits in Ihrer Frage angeben, besteht der Hauptunterschied zwischen union und struct ist das union Mitglieder überlagern die Erinnerung aneinander, so dass die Größe einer Gewerkschaft diejenige ist, während struct Elemente werden nacheinander ausgelegt (mit optionaler Polsterung dazwischen). Außerdem ist eine Union groß genug, um alle ihre Mitglieder aufzunehmen, und hat eine Ausrichtung, die zu allen ihren Mitgliedern passt. Also sagen wir mal int kann nur an 2-Byte-Adressen gespeichert werden und ist 2 Bytes breit und lang kann nur an 4-Byte-Adressen gespeichert werden und ist 4 Bytes lang. Die folgende Vereinigung

union test {
    int a;
    long b;
}; 

könnte eine haben sizeof von 4 und eine Ausrichtungsanforderung von 4. Sowohl eine Union als auch eine Struktur können eine Auffüllung am Ende haben, aber nicht an ihrem Anfang. Das Schreiben in eine Struktur ändert nur den Wert des Elements, in das geschrieben wird. Wenn Sie an ein Mitglied einer Gewerkschaft schreiben, wird der Wert aller anderen Mitglieder ungültig. Sie können nicht darauf zugreifen, wenn Sie vorher nicht darauf geschrieben haben, andernfalls ist das Verhalten undefiniert. GCC stellt als Erweiterung zur Verfügung, die Sie tatsächlich von Mitgliedern einer Gewerkschaft lesen können, auch wenn Sie ihnen in letzter Zeit nicht geschrieben haben. Für ein Betriebssystem muss es keine Rolle spielen, ob ein Benutzerprogramm in eine Union oder in eine Struktur schreibt. Dies ist eigentlich nur eine Frage des Compilers.

Eine weitere wichtige Eigenschaft von union und struct ist, dass sie dies zulassen ein Zeiger auf sie kann auf Typen von beliebigen seiner Mitglieder zeigen. Es gilt also:

struct test {
    int a;
    double b;
} * some_test_pointer;

some_test_pointer kann zeigen int* oder double*. Wenn Sie eine Adresse vom Typ umwandeln test zu int*es zeigt auf sein erstes Mitglied, a, eigentlich. Dasselbe gilt auch für eine Gewerkschaft. Da eine Union immer die richtige Ausrichtung hat, können Sie eine Union verwenden, um das Zeigen auf einen Typ gültig zu machen:

union a {
    int a;
    double b;
};

Diese Union kann tatsächlich auf ein int und ein Double zeigen:

union a * v = (union a*)some_int_pointer;
*some_int_pointer = 5;
v->a = 10;
return *some_int_pointer;    

tatsächlich gültig ist, wie es der C99-Standard festlegt:

Auf den gespeicherten Wert eines Objekts darf nur durch einen lvalue-Ausdruck zugegriffen werden, der einen der folgenden Typen hat:

  • ein Typ, der mit dem effektiven Typ des Objekts kompatibel ist
  • ein Aggregat- oder Union-Typ, der einen der oben genannten Typen in seinen Membern enthält

Der Compiler optimiert die nicht v->a = 10; da es den Wert beeinflussen könnte *some_int_pointer (und die Funktion kehrt zurück 10 Anstatt von 5).

Benutzeravatar von Krzysztof Voss
Krzysztof Voß

EIN union ist in einigen Szenarien nützlich.
union kann ein Werkzeug für Manipulationen auf sehr niedriger Ebene sein, wie das Schreiben von Gerätetreibern für einen Kernel.

Ein Beispiel dafür ist das Sezieren von a float Nummer durch Verwendung union von a struct mit Bitfeldern und a float. Ich speichere eine Nummer in der floatund später kann ich auf bestimmte Teile der zugreifen float dadurch struct. Das Beispiel zeigt wie union wird verwendet, um Daten aus verschiedenen Blickwinkeln zu betrachten.

#include <stdio.h>                                                                                                                                       

union foo {
    struct float_guts {
        unsigned int fraction : 23;
        unsigned int exponent : 8;
        unsigned int sign     : 1;
    } fg;
    float f;
};

void print_float(float f) {
    union foo ff;
    ff.f = f;
    printf("%f: %d 0x%X 0x%X\n", f, ff.fg.sign, ff.fg.exponent, ff.fg.fraction);

}

int main(){
    print_float(0.15625);
    return 0;
}

Schauen Sie sich an mit einfacher Genauigkeit Beschreibung auf Wikipedia. Ich habe das Beispiel und die magische Zahl 0,15625 von dort verwendet.


union kann auch verwendet werden, um einen algebraischen Datentyp zu implementieren, der mehrere Alternativen hat. Ich habe ein Beispiel dafür in dem Buch „Real World Haskell“ von O’Sullivan, Stewart und Goerzen gefunden. Überprüfen Sie es in der Die diskriminierte Gewerkschaft Sektion.

Prost!

Benutzeravatar von Avag Sargsyan
Avag Sargsjan

Ja, der Hauptunterschied zwischen struct und union ist derselbe, den Sie angegeben haben. Struct verwendet den gesamten Speicher seines Mitglieds und Union verwendet den größten Speicherbereich des Mitglieds.

Aber der ganze Unterschied liegt im Nutzungsbedarf des Speichers. Die beste Verwendung der Vereinigung kann in den Prozessen von Unix gesehen werden, wo wir Signale verwenden. wie ein Prozess nur auf ein Signal gleichzeitig reagieren kann. Die allgemeine Erklärung lautet also:

union SIGSELECT
{
  SIGNAL_1 signal1;
  SIGNAL_2 signal2;
  .....
};

In diesem Fall verwendet der Prozess nur den höchsten Speicher aller Signale. aber wenn Sie in diesem Fall struct verwenden, ist die Speichernutzung die Summe aller Signale. Macht viel Unterschied.

Zusammenfassend sollte Union ausgewählt werden, wenn Sie wissen, dass Sie gleichzeitig auf eines der Mitglieder zugreifen.

Benutzeravatar von friol
Friol

Union” und “Struktur” sind konstruiert der C-Sprache. Es ist unangemessen, von einem Unterschied zwischen ihnen auf “Betriebssystemebene” zu sprechen, da es sich um die Compiler das erzeugt unterschiedlichen Code, wenn Sie das eine oder andere Schlüsselwort verwenden.

1427860cookie-checkUnterschied zwischen einer Struktur und einer Union

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy