it-swarm.com.de

Unterschied zwischen einer Struktur und einer Union

Gibt es ein gutes Beispiel für den Unterschied zwischen einem struct und einem union? Grundsätzlich weiß ich, dass struct den gesamten Speicher des Mitglieds verwendet und union den größten Speicherplatz für Mitglieder verwendet. Gibt es einen anderen Unterschied in der Betriebssystemstufe?

385
gagneet

Bei einer Gewerkschaft sollten Sie nur eines der Elemente verwenden, da sie alle an derselben Stelle gespeichert sind. Dies ist nützlich, wenn Sie einen von mehreren Typen speichern möchten. Andererseits hat eine Struktur einen separaten Speicherplatz für jedes ihrer Elemente und sie können alle gleichzeitig verwendet werden.

Um ein konkretes Beispiel für ihre Verwendung zu geben, habe ich vor einiger Zeit an einem Scheme-Interpreter gearbeitet und die Scheme-Datentypen im Wesentlichen den C-Datentypen überlagert. Dies beinhaltete das Speichern einer Aufzählung in einer Struktur, die den Werttyp angibt, und einer Vereinigung 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

edit: Wenn Sie sich fragen, in welche Einstellung x.b auf 'c' der Wert von x.a geändert wird, ist er technisch gesehen undefiniert. Auf den meisten modernen Maschinen ist ein Zeichen 1 Byte und ein Int 4 Byte. Wenn Sie also x.b den Wert 'c' geben, gibt dies auch dem ersten Byte von x.a denselben Wert:

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

druckt

99, 99

Warum sind die beiden Werte gleich? Da die letzten 3 Bytes von int 3 alle Null sind, lautet sie auch 99. Wenn wir für x.a eine größere Zahl eingeben, werden Sie feststellen, dass dies nicht immer der Fall ist:

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

druckt

387427, 99

Um einen genaueren Blick auf die tatsächlichen Speicherwerte zu werfen, setzen wir die Werte in hexadezimaler Schreibweise und drucken sie aus:

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

druckt

deadbe22, 22

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

[~ # ~] aber [~ # ~]

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

Weitere Informationen zum Sortieren von Bytes finden Sie unter endianness .

643
Kyle Cronin

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;
}

reserviert mindestens (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) Bytes im Speicher für jede Instanz. ("Zumindest", weil Einschränkungen bei 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;
}

ordnet einen Teil des Speichers zu und gibt ihm vier Aliase. Also sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)), wieder mit der Möglichkeit, einige Alignments hinzuzufügen.

77
Charlie Martin

Gibt es ein gutes Beispiel für den Unterschied zwischen einer "Struktur" und einer "Union"?

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, jedoch nicht beide. Kurz gesagt, Gewerkschaften erlauben es, dass derselbe Speicherort mehr als einen Datentyp repräsentiert, wobei garantiert ist, dass Sie immer nur einen der Datentypen gleichzeitig speichern möchten.

Gewerkschaften sind größtenteils ein Detail auf niedriger Ebene, das auf dem Erbe von C als Systemprogrammiersprache basiert, in der manchmal "überlappende" Speicherorte auf diese Weise verwendet werden. Sie können manchmal Gewerkschaften verwenden, um Speicher zu speichern, in dem 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 Gewerkschaften und kennt diese nicht. Beide sind lediglich Speicherblöcke. Eine Struktur ist ein Speicherblock, in dem mehrere Datenobjekte gespeichert werden, bei denen sich diese Objekte nicht überlappen. Eine Union ist ein Speicherblock, in dem mehrere Datenobjekte gespeichert sind, der jedoch nur für die größten Datenobjekte gespeichert ist. Somit kann immer nur eines der Datenobjekte gespeichert werden.

49
cygil

Wie Sie bereits in Ihrer Frage dargelegt haben, besteht der Hauptunterschied zwischen union und struct darin, dass union Mitglieder die Erinnerung überlagern, sodass die Größe einer Union diejenige ist , während struct Mitglieder nacheinander angeordnet werden (mit optionalem Abstand dazwischen). Eine Gewerkschaft ist auch groß genug, um alle ihre Mitglieder aufzunehmen und eine Ausrichtung zu haben, die allen ihren Mitgliedern entspricht. Nehmen wir also an, int kann nur an 2-Byte-Adressen gespeichert werden und ist 2 Byte breit, und long kann nur an 4-Byte-Adressen gespeichert werden und ist 4 Byte lang. Die folgende Vereinigung

union test {
    int a;
    long b;
}; 

könnte einen sizeof von 4 und eine Ausrichtungsanforderung von 4 haben. Sowohl eine Vereinigung als auch eine Struktur können am Ende, jedoch nicht am Anfang, einen Abstand aufweisen. Das Schreiben in eine Struktur ändert nur den Wert des Members, in das geschrieben wurde. Wenn Sie einem Gewerkschaftsmitglied schreiben, wird der Wert aller anderen Mitglieder ungültig. Sie können nicht darauf zugreifen, wenn Sie zuvor noch nicht darauf geschrieben haben. Andernfalls ist das Verhalten undefiniert. GCC bietet eine Erweiterung, die Sie tatsächlich von Mitgliedern einer Gewerkschaft lesen können, auch wenn Sie ihnen in letzter Zeit noch nichts 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 ein Problem des Compilers.

Eine weitere wichtige Eigenschaft von union und struct ist, dass ein Zeiger auf sie kann auf Typen von beliebigen Mitgliedern verweisen. Es gilt also:

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

some_test_pointer kann auf int* oder double* zeigen. Wenn Sie eine Adresse vom Typ test in int* Umwandeln, verweist sie tatsächlich auf das erste Element, a. Gleiches gilt auch für eine Gewerkschaft. Da eine Vereinigung immer die richtige Ausrichtung hat, können Sie sie 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 verweisen:

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

ist tatsächlich gültig, wie in der C99-Norm angegeben:

Auf den gespeicherten Wert eines Objekts darf nur mit einem Werteausdruck eines der folgenden Typen zugegriffen werden:

  • ein Typ, der mit dem effektiven Typ des Objekts kompatibel ist
  • ...
  • ein Aggregat- oder Vereinigungstyp, der einen der oben genannten Typen unter seinen Mitgliedern umfasst

Der Compiler optimiert v->a = 10; Nicht, da dies den Wert von *some_int_pointer Beeinflussen könnte (und die Funktion 10 Anstelle von 5 Zurückgibt).

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

Ein Beispiel hierfür ist das Zerlegen einer float -Zahl mithilfe von union eines struct mit Bitfeldern und einem float. Ich speichere eine Nummer in float und kann später über diesen float auf bestimmte Teile des struct zugreifen. Das Beispiel zeigt, wie union verwendet wird, um unterschiedliche Blickwinkel auf Daten zu haben.

#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 single precision description auf Wikipedia an. Ich habe das Beispiel und die magische Nummer 0.15625 von dort verwendet.


union kann auch verwendet werden, um einen algebraischen Datentyp mit mehreren Alternativen zu implementieren. Ein Beispiel dafür fand ich in dem Buch "Real World Haskell" von O'Sullivan, Stewart und Goerzen. Lesen Sie den Abschnitt Die diskriminierte Vereinigung .

Prost!

18
Krzysztof Voss

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 Speicherplatz für Mitglieder.

Der Unterschied liegt jedoch in der Nutzung des Speichers. Die beste Nutzung der Union zeigt sich in den Unix-Prozessen, in denen wir Signale verwenden. Als ob ein Prozess immer nur auf ein Signal gleichzeitig einwirken 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. Wenn Sie in diesem Fall struct verwenden, ist die Speichernutzung die Summe aller Signale. Macht einen großen Unterschied.

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

11
Ravi Kanth

"nion" und "struct" sind Konstrukte der C-Sprache. Es ist unangemessen, von einem Unterschied auf "Betriebssystemebene" zu sprechen, da der Compiler anderen Code erzeugt, wenn Sie das eine oder andere Schlüsselwort verwenden.

11

Nichttechnisch bedeutet:

Annahme: Stuhl = Speicherblock, Personen = Variable

Struktur: Wenn 3 Personen anwesend sind, können sie entsprechend auf einem Stuhl ihrer Größe sitzen.

nion: Wenn 3 Personen anwesend sind nur eine Person, müssen alle denselben Stuhl benutzen, wenn sie sitzen möchten.

Technisch bedeutet:

Das unten genannte Programm gibt einen tiefen Einblick in Struktur und Einheit.

struct MAIN_STRUCT
{
UINT64 bufferaddr;   
union {
    UINT32 data;
    struct INNER_STRUCT{
        UINT16 length;  
        UINT8 cso;  
        UINT8 cmd;  
           } flags;
     } data1;
};

MAIN_STRUCT gesamt size = sizeof (UINT64) für bufferaddr + sizeof (UNIT32) für union + 32 Bit für padding (abhängig von der Prozessorarchitektur) = 128 Bit. Für die Struktur erhalten alle Mitglieder den Speicherblock zusammenhängend.

Union erhält einen Speicherblock des Mitglieds mit maximaler Größe (hier sind es 32 Bit). Innerhalb der Union liegt eine weitere Struktur (INNER_STRUCT), deren Mitglieder einen Speicherblock mit einer Gesamtgröße von 32 Bit (16 + 8 + 8) erhalten. In Union kann entweder auf INNER_STRUCT (32 Bit) -Mitglied oder Daten (32 Bit) zugegriffen werden.

11
skanda93

Du hast es, das ist alles. Aber wozu sind die Gewerkschaften eigentlich gut?

Sie können den gleichen Standortinhalt unterschiedlicher Typen einfügen. Sie müssen wissen den Typ dessen, was Sie in der Union gespeichert haben (so oft setzen Sie es in ein struct mit einem Typ-Tag ...).

Warum ist das wichtig? Nicht wirklich für Raumgewinne. Ja, Sie können ein bisschen mehr bekommen oder etwas auffüllen, aber das ist nicht mehr der Hauptpunkt.

Es dient der Typensicherheit und ermöglicht Ihnen das Ausführen einer Art dynamischer Typisierung: Der Compiler weiß, dass Ihre Inhalte unterschiedliche Bedeutungen haben können und die genaue Bedeutung, wie Sie sie zur Laufzeit interpretieren. Wenn Sie einen Zeiger haben, der auf verschiedene Typen zeigen kann, MÜSSEN Sie eine Vereinigung verwenden, andernfalls ist Ihr Code möglicherweise aufgrund von Aliasing-Problemen falsch (der Compiler sagt sich: "Oh, nur dieser Zeiger kann auf diesen Typ zeigen, damit ich optimieren kann raus diese Zugriffe ... ", und schlimme Dinge können passieren).

10
Piotr Lesnicki

Eine Struktur ordnet die Gesamtgröße aller darin enthaltenen Elemente zu.

Eine Gewerkschaft weist nur so viel Speicher zu, wie ihr größtes Mitglied benötigt.

9
CMS

Die Verwendung von union Unions werden häufig verwendet, wenn spezielle Typkonversationen erforderlich sind. Sich ein Bild von der Nützlichkeit der Vereinigung machen. Die c/c-Standardbibliothek definiert keine Funktion, die speziell zum Schreiben kurzer Ganzzahlen in eine Datei entwickelt wurde. Die Verwendung von fwrite () verursacht für eine einfache Operation einen übermäßigen Overhead. Mit einer Union können Sie jedoch problemlos eine Funktion erstellen, die eine Binärzahl einer kurzen Ganzzahl byteweise in eine Datei schreibt. Ich gehe davon aus, dass kurze Ganzzahlen 2 Byte lang sind

DAS BEISPIEL:

#include<stdio.h>
union pw {
short int i;
char ch[2];
};
int putw(short int num, FILE *fp);
int main (void)
{
FILE *fp;
fp fopen("test.tmp", "wb ");
putw(1000, fp); /* write the value 1000 as an integer*/
fclose(fp);
return 0;
}
int putw(short int num, FILE *fp)
{
pw Word;
Word.i = num;
putc(Word.c[0] , fp);
return putc(Word.c[1] , fp);
}    

obwohl putw () mit einer kurzen Ganzzahl aufgerufen wurde, war es möglich, putc () und fwrite () zu verwenden. Aber ich wollte ein Beispiel zeigen, um zu zeigen, wie eine Gewerkschaft verwendet werden kann

3
Ahmed

was ist der Unterschied zwischen Struktur und Union?

Die Abkürzung lautet: Die Rücksichtnahme liegt in der Speicherzuordnung. Erläuterung: In der Struktur wird Speicherplatz für alle Mitglieder in der Struktur erstellt. In Union wird Speicherplatz nur für ein Mitglied erstellt, das den größten Speicherplatz benötigt. Betrachten Sie den folgenden Code:

struct s_tag
{
   int a; 
   long int b;
} x;

union u_tag
{
   int a; 
   long int b;
} y;

Hier gibt es zwei Mitglieder innerhalb von struct und union: int und long int. Der Speicherplatz für int ist: 4 Byte und der Speicherplatz für long int ist: 8 im 32-Bit-Betriebssystem.

Also werden für Struktur 4 + 8 = 12 Bytes erzeugt, während 8 Bytes für Vereinigung erzeugt werden

Codebeispiel:

#include<stdio.h>
struct s_tag
{
  int a;
  long int b;
} x;
union u_tag
{
     int a;
     long int b;
} y;
int main()
{
    printf("Memory allocation for structure = %d", sizeof(x));
    printf("\nMemory allocation for union = %d", sizeof(y));
    return 0;
}

Ref: http://www.codingpractise.com/home/c-programming/structure-and-union/

die Struktur ist eine Sammlung verschiedener Datentypen, in denen sich unterschiedliche Datentypen befinden können und jeder seinen eigenen Speicherblock erhält

normalerweise verwenden wir union, wenn wir sicher sind, dass nur eine der Variablen gleichzeitig verwendet wird und Sie den vorhandenen Speicher voll ausnutzen möchten, da nur ein Speicherblock vorhanden ist, der dem größten Typ entspricht.

struct emp
{
    char x;//1 byte
    float y; //4 byte
} e;

gesamtspeicher bekommt es => 5 Byte

union emp
{
    char x;//1 byte
    float y; //4 byte
} e;

gesamtspeicher = 4 Byte

3
Anurag Bhakuni

Eine Union unterscheidet sich von einer Struktur, die von einer Union über die anderen wiederholt wird: Sie definiert denselben Speicher neu, während die Struktur ohne Überlappungen oder Neudefinitionen nacheinander definiert wird.

1
Dennis Ng

Vereinigungen sind praktisch, wenn Sie eine Byte-Bestellfunktion schreiben, die unten angegeben ist. Mit structs ist das nicht möglich.

int main(int argc, char **argv) {
    union {
        short   s;
        char    c[sizeof(short)];
    } un;

    un.s = 0x0102;

    if (sizeof(short) == 2) {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
    } else
        printf("sizeof(short) = %d\n", sizeof(short));

    exit(0);
}
// Program from Unix Network Programming Vol. 1 by Stevens.
1