unionen
-
union nix { double d; int i; }; int main() { union nix garnix = {1}; printf ("%d", garnix.i); return 0; }
Ausgabe: 0
ich dachte, die speicherbereiche überlappen sich quasi bei unionen.
darunter verstehe ich einen einzigen speicherplatz, der dem größten datentypen in einer union entspricht.
warum wird hier also 0 und nicht 1 ausgegeben?
wegen dem little endian format?
-
Weil nicht spezifiziert ist, wie der Compiler die Initial-Bitrepräsentation in einer union für double auf int umwandelt.
-
Erst einmal ist es undefiniertes Verhalten, erst das eine Feld einer Union zu beschreiben und dann ein anderes Feld zu lesen. Vermutlich, um genau diese Frage nicht aufkommen zu lassen
.
Bei vielen ( = praktisch allen) C-Implementierungen kannst du dich jedoch darauf verlassen, dass die ganzen Hacks mit unions funktionieren, die man immer sieht. Man muss bloß verstehen, wie sie funktionieren und sich genau auskennen:
Auf vielen Systemen ist double 64 Bit lang, int 32 Bit. Dann ist deine union in der Regel so aufgebaut:^ ^ ^ Byte 0 Byte 3 Byte 7 Anfang der Union Ende der Union Anfang von d Ende von d Anfang von i Ende von i
Wenn du nun den double Wert 1 in die union schreibst, ist das im weit verbreiteten IEEE 754 Format:
http://www.binaryconvert.com/result_double.html?decimal=04900111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000
Deine Maschine ist mit sehr hoher Wahrscheinlichkeit ein x86(-64), dieser benutzt ein little endian Format, speichert also
00000000 00000000 00000000 00000000 00000000 00000000 11110000 00111111 ^ ^ ^ Byte 0 Byte 3 Byte 8
Und darum ist die Ausgabe 0.
Du siehst, du warst mit deiner Vermutung schon auf der richtigen Fährte, hier habe ich es noch einmal ausführlich erklärt, denn bei hardwarenahen Hacks muss man sich eben mit der Hardware auskennen. Daher ist es auch gut, das noch einmal ausführlich zu sehen.
P.S.: Umwandlungen von Fließkomma- zu Ganzzahl auf Maschinenebene sind übrigens sehr gewagt. Wie du siehst, hättest du niemals 1 heraus bekommen, selbst wenn die Datentypen gepasst hätten. Ich nehme an, das hättest du nicht erwartet? Mit einem 64-Bit Datentypen (bei mir long, auf 32-Bit-systemen oft auch long long) hättest du (wieder mit little Endian) 4607182418800017408 als Ausgabe erhalten, denn binär 0b11111111110000(noch 48 Nullen) = 4607182418800017408.
-
danke @wutz und uaaaaau
an seppj für die sehr ausführliche antwort!!
die gucke ich mir morgen an, heute bin ich schon zu matschig in der rübe vom vielen programmieren.
-
SeppJ schrieb:
P.S.: Umwandlungen von Fließkomma- zu Ganzzahl auf Maschinenebene sind übrigens sehr gewagt. Wie du siehst, hättest du niemals 1 heraus bekommen, selbst wenn die Datentypen gepasst hätten. Ich nehme an, das hättest du nicht erwartet?
ja, auf die idee bin ich nicht gekommen, mir die bitrepräsentation in double anzusehen.
vielen dank noch einmal für die tolle antwort!
-
SeppJ schrieb:
Erst einmal ist es undefiniertes Verhalten, erst das eine Feld einer Union zu beschreiben und dann ein anderes Feld zu lesen.
UB nur ab C99, in C89 nur implementierungsabhängiges Verhalten.