Wie hieß denn noch der Datentyp ?
-
Ich bin grade verzweifelt auf der Suche nach dem einen ADT von dem ich mal etwas hörte aber seinen Namen vergessen habe.
Der Datentyp kann zum Beispiel 2 Variablen unterschiedlichen Typs halten , man hat aber immer nur Zugriff auf den zuletzt gesetzen.
Und der Datentyp ist im Speicher immer so groß wie sein größtes Element.
Wie hieß das Schlüsselwort noch ? Mir will es einfach nicht einfallen :).
-
Bacid90210 schrieb:
Ich bin grade verzweifelt auf der Suche nach dem einen ADT von dem ich mal etwas hörte aber seinen Namen vergessen habe.
Der Datentyp kann zum Beispiel 2 Variablen unterschiedlichen Typs halten , man hat aber immer nur Zugriff auf den zuletzt gesetzen.
Und der Datentyp ist im Speicher immer so groß wie sein größtes Element.
Wie hieß das Schlüsselwort noch ? Mir will es einfach nicht einfallen :).Ich schätze mal, dass Du eine union meinst.
-
Ach danke , genau .
es wollte mir einfach nicht einfallen .
Debrain vom feinsten.thx
-
Und hier noch der obligatorische Hinweis: Benutz keine Unions. Sie sind böse.
-
wieso?
wenn man weiss, was man macht, ist das doch ok?!?wie würdest du denn sonst zum beispiel eine 4x4 matrix darstellen?
union Matrix { float mat[4][4]; struct m { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; };so kann man per array index zugreifen oder halt per variablen ansprache...
-
Skym0sh0 schrieb:
so kann man per array index zugreifen oder halt per variablen ansprache...
Kablämm! Wunderbares Beispiel wo es leicht krachen könnte. Die Packung von Einzelvariablen muss nicht zwangsläufig die gleiche sein wie bei einem Array.
-
Skym0sh0 schrieb:
wieso?
wenn man weiss, was man macht, ist das doch ok?!?Das sagen sie alle. Und irgendwann versteht man die Welt nicht mehr.
union Matrix { float mat[4][4]; struct m { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; };so kann man per array index zugreifen oder halt per variablen ansprache...
Mal ganz davon abgesehen, dass ich das nicht möchte und auch überhaupt keinen Sinn darin sehe, das über Variablennamen zu machen, ist das, was du vorhast, bereits undefiniertes Verhalten.
Edit: Als Ergänzung zu SeppJ: Selbst wenn garantiert wäre, dass das Padding gleich ist, wäre es trotzdem nicht legal, über m auf mat zuzugreifen. Das gäb bestimmt noch lustige Effekte, wenn der Compiler zu aggressiv optimiert.
-
Wie du selbst schon sagtest ist der Zugriff nur auf das zuletzt gesetzte Element definiert. Du kannst also nicht erst einen float-Member setzen und dann auf das Array zugreifen.
Besser in diesem Fall wäre eine kleine Klasse mit ein paar inline-Gettern, z.B.:
struct Matrix { float data[4][4]; float& _11() { return data[0][0]; } // ... };
-
Michael E. schrieb:
Selbst wenn garantiert wäre, dass das Padding gleich ist, wäre es trotzdem nicht legal, über m auf mat zuzugreifen.
Das verstehe ich jetzt nicht. Ist das nicht gerade Sinn und Zweck einer union?
-
Jockelx schrieb:
Michael E. schrieb:
Selbst wenn garantiert wäre, dass das Padding gleich ist, wäre es trotzdem nicht legal, über m auf mat zuzugreifen.
Das verstehe ich jetzt nicht. Ist das nicht gerade Sinn und Zweck einer union?
C++98 Kapitel 9.5 schrieb:
In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time.
Der einzige Sinn von Unions ist es, Speicher zu sparen.
-
Mmh...
Heisst das jetzt, dass in einer union zwar mehrere Member sein dürfen, aber pro Instanz nur ein Member genutzt werden darf?Ich bin etwas verwundert ,denn als Std-Beispiel für uinon hab ich sowas im Kopf
union blub { int32 bla; char bla1; char bla2; char bla3; char bla4; }zum setzen/lesen einzelner Byteteile in einem int.
Das wäre demnach auch quatsch, richtig?
-
Jockelx schrieb:
Mmh...
Heisst das jetzt, dass in einer union zwar mehrere Member sein dürfen, aber pro Instanz nur ein Member genutzt werden darf?Du darfst natürlich den Member ändern, den du nutzt. Aber der erste Zugriff auf einen anderen Member muss dann ein schreibender Zugriff sein.
Ich bin etwas verwundert ,denn als Std-Beispiel für uinon hab ich sowas im Kopf
union blub { int32 bla; char bla1; char bla2; char bla3; char bla4; }zum setzen/lesen einzelner Byteteile in einem int.
Das wäre demnach auch quatsch, richtig?Klappt zwar meistens (wenn man Endianness beachtet), ist aber nicht definiert.
-
Aha.
Werde ich zwar vermutlich wieder nur unter 'unions sind komisch und brauch ich nicht' abspeichern,
aber Danke für die Erklärung.
-
Skym0sh0 schrieb:
wieso?
wenn man weiss, was man macht, ist das doch ok?!?wie würdest du denn sonst zum beispiel eine 4x4 matrix darstellen?
union Matrix { float mat[4][4]; struct m { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; };so kann man per array index zugreifen oder halt per variablen ansprache...
U.u. dann wenn du eine Membervariable m definieren würdest und nicht einen Membertyp.
Persönlich bin ich von dem Paddingargument ja nicht überzeugt, selbst wenn der Wortlaut des Standards das erlaubt, scheint es mir doch gegen die Intention der Standardkomittes zu sprechen.
Wenn wir annehmen, dass Padding kein Problem darstellt, sehe ich allerdings keine Einwände hinsichtlich undefinierten Verhaltens.
Jockelx schrieb:
Mmh...
Heisst das jetzt, dass in einer union zwar mehrere Member sein dürfen, aber pro Instanz nur ein Member genutzt werden darf?Ich bin etwas verwundert ,denn als Std-Beispiel für uinon hab ich sowas im Kopf
zum setzen/lesen einzelner Byteteile in einem int.
Das wäre demnach auch quatsch, richtig?Gemeint ist sicher so etwas:
union blub { int32 bla; char blab[sizeof(int32)]; };Das ist unproblematisch.
-
camper schrieb:
Wenn wir annehmen, dass Padding kein Problem darstellt, sehe ich allerdings keine Einwände hinsichtlich undefinierten Verhaltens.
Ich hab zwar immer Angst, mich mit dir bzgl. des Standards anzulegen, aber wo siehst du eine Rechtfertigung, dass es nicht undefiniertes Verhalten sein soll?
Gemeint ist sicher so etwas:
union blub { int32 bla; char blab[sizeof(int32)]; };Das ist unproblematisch.
Nur was rauskommt, weiß man nicht
Ist es Big Endian oder Little Endian? Verhält char sich wie signed char oder wie unsigned char? Warum werden die Bits in einem Char nicht in einer anderen Reihenfolge interpretiert als bei einem int-Byte? Warum ist es überhaupt definiert?
-
camper schrieb:
Gemeint ist sicher so etwas:
union blub { int32 bla; char blab[sizeof(int32)]; };Das ist unproblematisch.
Wirklich? Ich hab ja gestern einiges gelernt über undefiniertes Verhalten (anderer Thread: http://www.c-plusplus.net/forum/286938 ), und wenn ich das hier mal anwende, dann könnte ein Compiler diese union folgendermaßen behandeln. Jeder Zugriff auf einen Member, der beweisbar vorher durch Schreibzugriff auf einen anderen Member invalidiert wurde, kann ignoriert werden, da er undefiniertes Verhalten auslöst. Das heißt z.B.
blub B; B.bla = 42; if (x != 0) B.blab[0] = 42; B.bla += x; // kann wegoptimiert werden, da die einzige legale Ablaufsequenz notwendig x==0 impliziertMir fällt auf die Schnelle kein besseres Beispiel ein, ich hoffe, es wird ungefähr klar, was ich meine.
-
Wozu denn dieses
union-Gefrickel, wenn man doch etwas ganz anderes erreichen möchte?int i = 12; char *p = reinterpret_cast<char *>(&i); if (*p == 12) ..
-
Bashar schrieb:
Wirklich? Ich hab ja gestern einiges gelernt über undefiniertes Verhalten (anderer Thread: http://www.c-plusplus.net/forum/286938 ), und wenn ich das hier mal anwende, dann könnte ein Compiler diese union folgendermaßen behandeln. Jeder Zugriff auf einen Member, der beweisbar vorher durch Schreibzugriff auf einen anderen Member invalidiert wurde, kann ignoriert werden, da er undefiniertes Verhalten auslöst.
Keineswegs, was beweist wie subtil die Sprache des Standards sein kann:
In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. [Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial
sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ]Nirgendwo steht hier, dass der lesende Zugriff über ein anders Member per se undefiniert wäre. Was hier steht ist, dass die anderen Member keine eigenen Wert haben und folglich, da auf das gleiche Objekt zugegriffen wird, das Ergebnis des Zugriffs vom Wert des zuletzt geschriebenen Members abhängt. Und das ist ausreichend, da zu jeder beliebigen Objektrepräsentation (die ja von allen Membern geteilt wird) eine eindeutige Wertrepräsentation gehört.
Undefiniert wird es erst durch die Einschränkungen, die in 3.10/15 zu finden sind (aliasing). In gewisser Weise dient der erste Satz nur dazu, dafür zu sorgen, dass die Aliasregeln überhaupt auf diesen Fall angewendet werden können, andernfalls wäre nämlich nicht klar, auf den Wert welchen Objektes überhaupt zugegriffen wird.Interesessant ist in diesem Zusammenhang die folgende Bemerkung (nicht normativ, was dort gesagt wird, könnten wir also auch aus anderen Regeln herleiten) - wenn alle POD-structs mit gleicher Anfangssequenz für diese Sequenz das gleiche Speicherlayout haben müssen, spricht das meiner Meinung nach stark dagegen, dass der Compiler (abgesehen vom Ende des structs) nach Belieben Padding einführen darf.
-
Michael E. schrieb:
Nur was rauskommt, weiß man nicht
Ist es Big Endian oder Little Endian? Verhält char sich wie signed char oder wie unsigned char? Warum werden die Bits in einem Char nicht in einer anderen Reihenfolge interpretiert als bei einem int-Byte? Warum ist es überhaupt definiert?Einige dieser Fragen werden durch den Standard geklärt, andere müssen von der jeweiligen Implementation definiert werden.
-
camper schrieb:
Nirgendwo steht hier, dass der lesende Zugriff über ein anders Member per se undefiniert wäre. Was hier steht ist, dass die anderen Member keine eigenen Wert haben und folglich, da auf das gleiche Objekt zugegriffen wird, das Ergebnis des Zugriffs vom Wert des zuletzt geschriebenen Members abhängt. Und das ist ausreichend, da zu jeder beliebigen Objektrepräsentation (die ja von allen Membern geteilt wird) eine eindeutige Wertrepräsentation gehört.
Du greifst aber nicht auf das Objekt, sondern auf einen Member des Objekts zu. Dass an dieser Stelle ein Bitmuster steht, macht den Zugriff nicht legal.
Interesessant ist in diesem Zusammenhang die folgende Bemerkung (nicht normativ, was dort gesagt wird, könnten wir also auch aus anderen Regeln herleiten) - wenn alle POD-structs mit gleicher Anfangssequenz für diese Sequenz das gleiche Speicherlayout haben müssen, spricht das meiner Meinung nach stark dagegen, dass der Compiler (abgesehen vom Ende des structs) nach Belieben Padding einführen darf.
Wieso?
camper schrieb:
Michael E. schrieb:
Nur was rauskommt, weiß man nicht
Ist es Big Endian oder Little Endian? Verhält char sich wie signed char oder wie unsigned char? Warum werden die Bits in einem Char nicht in einer anderen Reihenfolge interpretiert als bei einem int-Byte? Warum ist es überhaupt definiert?Einige dieser Fragen werden durch den Standard geklärt, andere müssen von der jeweiligen Implementation definiert werden.
Welche werden denn vom Standard geklärt?
-
PS: Hab noch ne schöne Anekdote gefunden:
Conversion by union can be a disaster. Been there, done that. The BSD kernel used
to have a union that essentially looked like this:union u {
char* c;
short* s;
int* i;
long* l;
};and used to be loosy goosy vax and store into one field and read back from another.
This was fine until we were porting to a machine that encodes the operand size in
the low order bits of the pointer. That led to some fun hunting.Quelle: http://www.velocityreviews.com/forums/t284331-p2-undefined-behaviour.html