Struct ohne Namen-Ersatz
-
leser schrieb:
struct { float x,y,z; }pos, *data;???
irgendwie hast du meine frage nicht verstanden
-
Pellaeon schrieb:
union AEVertex3 { struct { float x,y,z; }; float data[3]; } pos;Die struct da ohne Namen ist ja eigentlich nicht erlaubt.
Wie kann ich es nun machen, dass es standardkonform ist und ich denselben Effekt habe?Ich möchte als auf x auch so zugreifen können: pos.x, ohne das ich ne Strukurvariable habe und noch nen Namen dazwischen hätte (pos.einzeln.x <- so will ich es halt nicht)
MfG Pellaeon
das ist nicht möglich. zweck des unions soll ja offenbar sein, dass data[0] ein alias für x, data[1] alias für y und data[3] alias für z ist. ob das überhaupt durch den standard garantiert wird, ist nicht unumstritten. willst du der debatte entgehen und kannst auf die verwendung von x,y,z in initialisierungslisten verzichtn, böte sich die definition entsprechender memberfunktionen an, etwa
struct AEVertex3 { float data[3]; float& x() { return data[0]; } const float& x() const { return data[0]; } float& y() { return data[1]; } const float& y() const { return data[1]; } float& z() { return data[2]; } const float& z() const { return data[2]; } };zwar währen dann immer noch die klammern für den funktionsaufruf zu schreiben, aber das dürfte eine vergleichsweise geringe belastung darstellen. bist du sicher, dass das aliasing funktioniert, könnte man statt dessen auch auf data als membervariable verzichten:
struct AEVertex3 { float x,y,z; float(&)[3] data() { return reinterpret_cast<float(&)[3]>(*this); } const float(&)[3] data() const { return reinterpret_cast<const float(&)[3]>(*this); } };
-
Du könntest auch den [] Operator überladen...
#include <iostream> using namespace std; struct AEVertex3 { float x,y,z; float& operator [] (int index) { return (&x)[index]; } } pos; int main(int argc, char* argv[]) { pos.x = 1; pos.y = 10; pos[2] = 20; cout<<pos[1]<<endl; cout<<pos.z<<endl; }Vielleicht nicht ganz das, was du willst, aber auch eine Möglichkeit.
Edit: kleines Update
-
Wie wär's mit sowas:
struct Vertex { float data[3]; float& x; float& y; float& z; Vertex(): x( data[0] ), y( data[1] ), z( data[2] ) {} };Bin mir zwar nicht sicher, ob Referenzen auf Arraymitglieder erlaubt sind, aber keiner meiner Compiler meckert und es kommt das raus was ich erwarten würde...
int main(void) { Vertex xyz; xyz.data[0] = 10; xyz.data[1] = 20; xyz.data[2] = 30; cout << xyz.x << xyz.y << xyz.z << endl; }
-
LordJaxom schrieb:
Wie wär's mit sowas:
struct Vertex { float data[3]; float& x; float& y; float& z; Vertex(): x( data[0] ), y( data[1] ), z( data[2] ) {} };Bin mir zwar nicht sicher, ob Referenzen auf Arraymitglieder erlaubt sind, aber keiner meiner Compiler meckert und es kommt das raus was ich erwarten würde...
legal ist das schon, aber aus 2 gründen ungünstig:
1. typischerweise werden diese referenzmitglieder zusätzlich speicher verbrauchen und den zugriff auf x,y,z wegen der indirektion möglicherweise verlangsamen, und, was schwerer wiegt,
2. Vertex ist kein POD mehr und ist auch nicht mehr normal kopierbar wegen seiner referenzmitglieder (der implizite definitierte copy-ctor existiert zwar, macht aber nicht das, was wir wollen, und zuweisung ist unmöglich), hier müsste man also zusätzlich noch weitere funktionen geschrieben werden - das ergebnis ist bei so einer klasse, die aller wahrscheinlichkeit in großen mengen gebraucht wird, höchstwahrscheinlich ein langsamerer programmablauf. ausserdem besteht ein loch hinsichtlich const-correctness: für ein konstantes vertex sind x,yz immer noch veränderbar.
-
ok, danke für die Antworten

-
Pellaeon schrieb:
union AEVertex3 { struct { float x,y,z; }; float data[3]; } pos;Die struct da ohne Namen ist ja eigentlich nicht erlaubt.
Nicht? Also laut:
http://www.cplusplus.com/doc/language/tutorial/other_data_types.html
schonUnd der D3DVECTOR von DirectX ist genauso aufgebaut. Und es funktioniert. Macht schliesslich auch sinn.
@Camper: wo findet denn die Debatte statt?
Grüssli
-
keine Fragen mehr.
-
Dravere schrieb:
Pellaeon schrieb:
union AEVertex3 { struct { float x,y,z; }; float data[3]; } pos;Die struct da ohne Namen ist ja eigentlich nicht erlaubt.
Nicht? Also laut:
http://www.cplusplus.com/doc/language/tutorial/other_data_types.htmlunbenannte structs sind nat. erlaubt, anonyme structs (analog zu anonymen unions) dagegen nicht. aus dem text ergib sich, das letzteres gemeint war.
Und der D3DVECTOR von DirectX ist genauso aufgebaut. Und es funktioniert. Macht schliesslich auch sinn.
a.k.a. spracherweiterung des compilers

@Camper: wo findet denn die Debatte statt?
das ist ein gelegentlich immer wieder auftauchendes problem. das zugrundeliegende problem ist die frage, inwieweit dem compiler freiheiten hinsichtlich paddings innerhalb von strukturen eingeräumt werden.
Helmut S. schrieb:
typedef union AEVertex3_tag{float data[3] ;float x, y, z;}AEVertex3;dummerweise sind dann auch y und z synonym zu x bzw. data[0]
dem compiler ist es egal, ob du mehrere member in einer deklaration deklarierst, oder dies jeweils einzeln durchführst.
-
Ja, ich hatte mich geirrt. Jetzt würd ich es so lösen.
struct AEVertex3{ float x, y, z, *data; AEVertex3() : data(&x){} }pos; int main() { pos.y = 7.0; float test = pos.data[1]; }
-
camper schrieb:
unbenannte structs sind nat. erlaubt, anonyme structs (analog zu anonymen unions) dagegen nicht. aus dem text ergib sich, das letzteres gemeint war.
Also:
class CIrgendwas { union { struct { float x, y, z; }; float data[3]; }; }ist nicht erlaubt? Funktioniert bei mir aber wunderbar. Oder liegt das am Compiler VS2003? Oder hab ich wieder was falsch verstanden?
Grüssli
-
liegt am Compiler. Ich habe VS 2005 und als ich die Warnungen auf Stufe 4 festellt habe, kamm halt der Hinweis, dass dieses struct nicht standardkonform ist.
-
Gibts nen Windowscompiler der das nicht kann? Mir fällt keiner ein.
Finde es eigentlich schade, dass es laut Standard keine Möglichkeit gibt zu bestimmen wie Variablen im Speicher liegen sollen.
-
Helmut S. schrieb:
Ja, ich hatte mich geirrt. Jetzt würd ich es so lösen.
struct AEVertex3{ float x, y, z, *data; AEVertex3() : data(&x){} }pos; int main() { pos.y = 7.0; float test = pos.data[1]; }
und wieder brauchen wir noch unseren eigenen copy-ctor und copy-zuweisung. und da diese structur kein POD ist, wird die angelegenheit tatsächlich ziemlich undefiniert. 9.2/12 garantiert nur, dass &this->x < &this->y gilt. das ist zuwenig, um eine anordnung äquivalent zu einem array zu garantieren.
Dravere schrieb:
ist nicht erlaubt? Funktioniert bei mir aber wunderbar. Oder liegt das am Compiler VS2003? Oder hab ich wieder was falsch verstanden?
probier das ganze mal mit der compilerswitch /Za (windows-header u.ä. fällt dann allerdings aus).
-
camper schrieb:
und da diese structur kein POD ist, wird die angelegenheit tatsächlich ziemlich undefiniert. 9.2/12 garantiert nur, dass &this->x < &this->y gilt. das ist zuwenig, um eine anordnung äquivalent zu einem array zu garantieren.
"Füll-Byte stehen doch nicht irgendwo innerhalb einer Struktur"
Der Compiler sorgt dafür, dass Strukturelemente grundsätzlich auf Adressen ausgerichtet sind, die für
den Datentyp und die Prozessoren "natürlich" sind. Dieses Prinzip ist Voraussetzung für portablen Code.
Ausgerichtet werden, char an Byte-Grenzen, short an geraden Byte-Grenzen, int an 32-Bit-Grenzen usw.,
Strukturen an der grössten Ausrichtungssgrenze der beteiligten Elemente und Unions, wie vom ersten Element
der Union gefordert.
Füll-Bytes stehen doch nicht irgendwo innerhalb einer Struktur, sondern an bestimmten Stellen - beim Wechsel
der Datentypen (wenn notwendig) oder am Ende einer Struktur, oder wenn z.B. mit /Zp oder #pragma pack
Füllzeichen bis zur Standardkomprimierungsgrösse dazukommen.
Wenn ich mir die Strukturgrössen mit verschiedenen template-Argumenten betrachte, der Compiler folgt strikt
den Ausrichtungs-Richtlinien für alle win32-Zielprozessoren und garantiert mir, dass die Zugriffe mittels Zeiger funktionieren.#include<iostream> #include <string> using namespace std; template <typename T> struct AEVertex3{ T x, y, z, *data; AEVertex3() : data(&x){} AEVertex3(const AEVertex3& a){ data = &x; x = a.x; y = a.y; z = a.z; } AEVertex3& operator= (const AEVertex3& a){ data = &x; x = a.x; y = a.y; z = a.z; return *this; } }; int main() { size_t s1 = sizeof (AEVertex3<unsigned char>); // s1 = 8 size_t s2 = sizeof (AEVertex3<char>); // s2 = 8 size_t s3 = sizeof (AEVertex3<wchar_t>); // s3 = 12 size_t s4 = sizeof (AEVertex3<short>); // s4 = 12 size_t s5 = sizeof (AEVertex3<int>); // s5 = 16 size_t s6 = sizeof (AEVertex3<float>); // s6 = 16 size_t s7 = sizeof (AEVertex3<double>); // s7 = 32 size_t s8 = sizeof (AEVertex3<string>); // s8 = 100 AEVertex3<string> adr; adr.data[0] = "Hans "; adr.data[1] = "Maier, "; adr.data[2] = "Bergen"; cout << adr.x << adr.y << adr.z << endl; return 0; }
-
Helmut S. schrieb:
"Füll-Byte stehen doch nicht irgendwo innerhalb einer Struktur"
Der Compiler sorgt dafür, dass Strukturelemente grundsätzlich auf Adressen ausgerichtet sind, die für
den Datentyp und die Prozessoren "natürlich" sind. Dieses Prinzip ist Voraussetzung für portablen Code.
Ausgerichtet werden, char an Byte-Grenzen, short an geraden Byte-Grenzen, int an 32-Bit-Grenzen usw.,
Strukturen an der grössten Ausrichtungssgrenze der beteiligten Elemente und Unions, wie vom ersten Element
der Union gefordert.
Füll-Bytes stehen doch nicht irgendwo innerhalb einer Struktur, sondern an bestimmten Stellen - beim Wechsel
der Datentypen (wenn notwendig) oder am Ende einer Struktur, oder wenn z.B. mit /Zp oder #pragma pack
Füllzeichen bis zur Standardkomprimierungsgrösse dazukommen.
Wenn ich mir die Strukturgrössen mit verschiedenen template-Argumenten betrachte, der Compiler folgt strikt
den Ausrichtungs-Richtlinien für alle win32-Zielprozessoren und garantiert mir, dass die Zugriffe mittels Zeiger funktionieren.in diesem forum geht es primär um das, was durch den standard abgedeckt ist - das verhalten einer konkreten implmementation kann bestenfalls als beleg dür eine bestimmte interpretation dienen. der erwähnt absatz ist meines wissens der einzige, der konkrete aussagen über das layout von strukturen, die keine PODs sind, macht. er enthält auch noch eine eine aufzählung möglicher gründe, die für zusätzliches padding sorgen können.
ISO/IEC 14882:2003 schrieb:
Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
die wortwahl deutet aber an, dass diese liste nicht aussschließlich zu verstehen ist.
für PODs dagegen gibt es einige weitere regeln:ISO/IEC 14882:2003 schrieb:
9.2/17
A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]Insebsondere die Notiz ist dabei interessant, denn das läßt sich ohne weiteres so interpretieren, dass padding dann, und nur dann, auftreten soll, wenn das alignment des folgenden member (oder am ende, da sizeof T ein vielfaches des alignments von T sein muss, um den regln für das layout für arrays zu entsprechen) dies erfordert, und dann nur soweit, wie minimal nötig ist. das bedeutet nebenbei, dass PODs mit lokal modifierzierter #pragma pack einstellung bereits konstrukte sind, die nicht mehr durch den standard abgedeckt werden. wenn pack dabei zu groß ist, deshalb, weil mehr padding als notwendig enthalten ist (und die kardinalsfrage ist eben, ob das erlaubt ist, oder nicht). eine einstellung, die für dichtere packung sorgt, verstößt dagegen bereits gegen
ISO/IEC 14882:2003 schrieb:
3.9/5
Object types have alignment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an implementation-defined integer value representing a number of bytes; an object is allocated at an address that meets the alignment requirements of its object type.denn alignment ist eine eigenschaft des typs und kommt jedem objekt dieses typs gleichermaßen zu. nebenbei sind zwei PODs, die korrespondierende member haben, layout-kompatibel - und auch das widerspricht der möglichkeit, die packungsdichte für einzelne strukturen verändern zu dürfen.
-
Lolz schrieb:
...Finde es eigentlich schade, dass es laut Standard keine Möglichkeit gibt zu bestimmen wie Variablen im Speicher liegen sollen.
Och, ich finde es gut, dass der Standard das der konkreten Compilerimplementierung und Plattform überlässt. Gäbe sonst nur Schwierigkeiten mit Hardware-Nähe und Portabilität (müsste auf eins von beiden verzichten)...

Gruß,
Simon2.