Sind Member linear in struct/Klasse?
-
Hallo,
sagen wir ich habe so eine struct:
struct Foo { float r,g,b,a; float* asArray() { return &r; } };Ist dann garantiert, dass die Membervariablen linear im Speicher liegen? Sprich: Wird die Methode asArray() absolut immer funktionieren?
-
bayernVSManUvorfreuer schrieb:
Hallo,
sagen wir ich habe so eine struct:struct Foo { float r,g,b,a; float* asArray() { return &r; } };Ist dann garantiert, dass die Membervariablen linear im Speicher liegen? Sprich: Wird die Methode asArray() absolut immer funktionieren?
Nach Standard: Nein.
Nach normalem Ermessen: Ja.
Ich würde es (wenn nur ums geh/gehtnicht geht) machen und mit ausreichen static_assert absichern. Ob ich's in Sachen Wenigfrickelndem Stil vertreten könnte, ist was anderes.
-
Wenn du die Member als Array ansprechen willst, dann nimm doch ein Array...

-
Ich habs jetzt so gemacht:
class Color { public: union { struct { float r, g, b, a; }; float channel[4]; }; };Passt das, oder kann das schief gehen?
-
Das gleiche Problem. Hast du meinen Post gelesen?
-
also im Normalfall liegen die Member einer Klasse/Struktur in der Reihenfolge hintereinander, wie man sie im Quelltext angegeben hat.
von daher sollte dein Ansatz funktionieren.allerdings solltest du auf das Alignment achten.
der Compiler neigt dazu Platzhalter in Strukturen/Klassen einzufügen (kA warum)
jedenfalls lässt sich das Alignment einstellen.schau mal hier zum Thema alignment:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-117530-and-view-is-previous.htmlalso die VC++ Lösung:
#pragma pack(push, 1) // Alignment von 1 (praktisch kein alignment) struct Foo { float r, g, b, a; float* asArray(void) { return &r; } }; #pragma pack(pop) // Default alignment
-
DrakoXP schrieb:
der Compiler neigt dazu Platzhalter in Strukturen/Klassen einzufügen (kA warum)
Performance (einfachere Berechnung des Offsets). Bei gleichen Membergrössen sollte Alignment eigentlich nicht auftreten, aber es ist halt nicht verboten.
-
Dann hab ich aber in diesem Code:
class Color { public: union { struct { float r, g, b, a; }; float channel[4]; }; };Auch das Problem mit Alignment, oder? Wenn das Alignment jetzt größer als 4 ist, dann werden nach jedem float in der Struct Füllbytes eingefügt und die Werte im Array channel korrespondieren dann nicht mehr mit den r,g,b,a werten (zB. ist &channel[1] nicht mehr gleich &g), oder?
PS: Hab gerade geschaut, in meinem VS08 ist "struct member alignment" auf default gestellt. Was genau bedeutet das? Dass der Compiler es selber nach Belieben für jede struct entscheiden kann?
-
warum das union? warum überhaupt die r,g,b,a und nicht das Array, wie ' schon vorgeschlagen hatte?
Wenns denn wirklich sein muss mach dir noch methoden dazu die dir ne referenz auf das jeweilige arrayelement liefern:class Color { private: float channel[4]; public: float* asArray() { return channel; } float& r() { return channel[0]; } float& g() { return channel[1]; } // usw. };Alles andere ist nicht portabel (auch die #pagmas nicht, die werden auf anderen Compilern ggf. einfach ignoriert)
-
pumuckl schrieb:
warum das union? warum überhaupt die r,g,b,a und nicht das Array, wie ' schon vorgeschlagen hatte?
Weil ich sehr, sehr häufig eben Zugriff auf rgba brauche. Und ich habe weder Lust ständig zu schreiben color.colors[2] + color.colors[3] + ... noch
colors.r() + colors.g() + ...
Portabilität ist mir auch völlig egal. Zielplattform ist ausschließlich Windows.
-
unions haben durchaus ihre Daseinsberechtigung.
Alignment ist normalerweise auch kein Problem.
Es wird immer das alignment des größten Members genommen.
Nur wenn du in deiner struct unterschiedlich große Typen hättest,
würds vielleicht interessant werden, aber wahrscheinlich nichtmal dann.Ausserdem sind unions ein Überbleibsel aus C und deshalb
imo portabler als Klassen.Mein DSP C compiler kann das auch.
EDIT: Portabilität zu 64bit würd mich interessieren,
aber wird dann nicht auch einfach die selbe alignment strategie
(kleinstmögliches aber größtes erwartetes)
angewandt und es kommt das selbe heraus?
-
Hab ein paar Tests gemacht und es scheint alles zu klappen. Passt

-
DrakoXP schrieb:
also im Normalfall liegen die Member einer Klasse/Struktur in der Reihenfolge hintereinander, wie man sie im Quelltext angegeben hat.
Was heißt denn "im Normalfall"? Ich zitiere nur mal eine boost-Dokumentation:
<a href= schrieb:
http://www.boost.org/doc/libs/1_39_0/libs/bimap/doc/html/boost_bimap/rationale.html#boost_bimap.rationale.general_design">
In order to use this, the compiler must conform to a layout-compatibility clause that is not currently in the standard but is very natural. The additional clause imposes that if we have two classes:struct class_a_b { Type1 name_a; Type2 name_b; }; struct class_b_a { Type1 name_b; Type2 name_a; };then the storage layout of class_a_b is equal to the storage layout of class_b_a. If you are surprised to learn that this does not hold in a standards-compliant C++ compiler, welcome to the club.
Felix
-
volkard schrieb:
bayernVSManUvorfreuer schrieb:
Hallo,
sagen wir ich habe so eine struct:struct Foo { float r,g,b,a; float* asArray() { return &r; } };Ist dann garantiert, dass die Membervariablen linear im Speicher liegen? Sprich: Wird die Methode asArray() absolut immer funktionieren?
Nach Standard: Nein.
Nach normalem Ermessen: Ja.
Ich würde es (wenn nur ums geh/gehtnicht geht) machen und mit ausreichen static_assert absichern. Ob ich's in Sachen Wenigfrickelndem Stil vertreten könnte, ist was anderes.Nachdem Foo hier ein POD ist, sagt der Standard da irgendwas vonwegen "compatible layout". Also gleich wie in C, wenn ich das richtig verstehe. Und in C ist es glaube ich garantiert. D.h. im Falle von PODs auch in C++.

(EDIT: WENN ich mich mit keiner dieser "Annahmen" irre, muss das heissen /EDIT)