Seite 1 von 2
C++ - Struct Padding/Alignment
Verfasst: Di Feb 28, 2012 12:07 pm
von fat-lobyte
Hallo.
Ich habe folgendes Problem: ich will eine Struktur anlegen, und diese dann Byte für Byte genau so im Speicher wiederfinden, wie sie im Quellcode steht.
Beispiel:
Ich möchte dann auf die Elemente der Struktur so zugreifen können:
Code: Alles auswählen
struct A s;
char a = * (char *) &s;
double b = *(double*) ((char *)&s + sizeof(char));
int c = *(int*) ((char *)&s + sizeof(char) + sizeof(double));
short d[7];
memcpy(d, ((char *)&s + sizeof(char) + sizeof(double) + sizeof(int)), sizeof(short)*7);
Bitte beachtet, ich will _nicht_ alignof() oder offsetoff() verwenden.
Warum der ganze Spaß?
Es geht darum, eine wohldefinierte Struktur über das Netzwerk zu verschicken. Leider ist das Speicher-Layout der Struktur in C/C++ nicht festgeschrieben, das heißt ich kann nicht einfach &s mit der länge sizeof(A) verschicken.
Was ich jetzt machen muss: Ich muss zusätzlichen Speicher anfordern, und dort manuell die Daten an die richtige Stelle schreiben. Ich hoffe, das geht besser.
Weiß jemand wie ich das erreichen kann, ohne mich in Compileroptionen und #pragma's zu verlieren?
Das ganze sollte am liebsten ganz Standard-C++ sein (C++11!) oder zumindest auf Clang, GCC und Microsoft C++ funktionieren.
Hat jemand Ideen?
Re: C++ - Struct Padding/Alignment
Verfasst: Di Feb 28, 2012 1:50 pm
von Xin
Diese Frage ist faszinierend in Kombination mit der Argumentation von Einfachheit beim Programmieren... ^^
Aber wir sind ja auch keine Anfänger mehr.
Wunsch:
Es gibt __packed beim GCC. Bei den anderen weiß ich das nicht.
Ich würde eine Klasse draus machen:
Code: Alles auswählen
class A
{
private:
char storage[ sizeof( char ) + sizeof( double ) + sizeof( int ) + sizeof( short) * 7 ];
unsigned int const posOfA = 0,
unsigned int const posOfB = sizeof( char );
unsigned int const posOfC = posOfB + sizeof( double );
...
public:
char getA() const { return storage[ posOfA ]; }
char setA( char value ) { return storage[ posOfA ] = value; }
double getB() const { return *static_cast< double * >( &storage[ posOfB ]; ) }
char setB( double value ) { return *static_cast< double * >( &storage[ posOfB ]; ) = value; }
}
Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 1:22 pm
von fat-lobyte
Xin hat geschrieben:Diese Frage ist faszinierend in Kombination mit der Argumentation von Einfachheit beim Programmieren... ^^
Ich würde sehr gerne auf Padding/Alignment vergessen, leider werden die Daten übers Netzwerk gesendet. Da muss alles ganz genau definiert sein
Xin hat geschrieben:Es gibt __packed beim GCC. Bei den anderen weiß ich das nicht.
Auf Compilererweiterungen würde ich gerne verzichten.
Xin hat geschrieben:Ich würde eine Klasse draus machen:
...
Danke für den Tip!
Ich versuche mit Variadic Templates und ein bisschen Meta-Programming sowas in die Richtung zu zaubern, funktioniert leider noch nicht so super:
Code: Alles auswählen
struct firstmember {}; // als NameTag, quasi der "name" des Members
struct secondmember {};
typedef PackedStruct<
int, firstmember, // deklaration: VarType, NameTag
double, secondmember
// ...
> MyStruct;
std::cout<<"Struct has size: "<<sizeof(MyStruct)<<'\n'; // 12 !
MyStruct s;
s.get<firstmember>() = 5;
std::cout<<"First member was set to: "<<s.get<firstmember>()<<'\n';
s.get(secondmember{}) = 3.0;
std::cout<<"Second member was set to: "<<s.get<secondmember>()<<'\n';
Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 1:44 pm
von Xin
fat-lobyte hat geschrieben:Xin hat geschrieben:Diese Frage ist faszinierend in Kombination mit der Argumentation von Einfachheit beim Programmieren... ^^
Ich würde sehr gerne auf Padding/Alignment vergessen, leider werden die Daten übers Netzwerk gesendet. Da muss alles ganz genau definiert sein

Hey, wenn ich Dir was auf's Butterbrot schmieren kann, dann mach ich das auch. Der alte Mann will ja auch was zu lachen
Das Problem ist mir schon bewusst.
fat-lobyte hat geschrieben:Xin hat geschrieben:Es gibt __packed beim GCC. Bei den anderen weiß ich das nicht.
Auf Compilererweiterungen würde ich gerne verzichten.
Sehe ich ähnlich, daher habe ich bisher __packed auch noch nie verwendet....
fat-lobyte hat geschrieben:Xin hat geschrieben:Ich würde eine Klasse draus machen:
...
Danke für den Tip!
... sondern derartige Probleme wie beschrieben gelöst. Das läuft auf allen mir bekannten Compilern.
Meine Array-Klasse arbeitet ebenfalls so, was den Vorteil hat, dass die zu speichernden Elemente im Gegensatz zu std::vector<> keinen Default-Konstruktor benötigen.
fat-lobyte hat geschrieben:Ich versuche mit Variadic Templates und ein bisschen Meta-Programming sowas in die Richtung zu zaubern, funktioniert leider noch nicht so super:
Ich habe mir den Code jetzt mal angeguckt und abgesehen davon dass ich "Variadic Templates" noch nicht kenne (ich muss mir mal 'ne Woche Urlaub nehmen und C++11 mal antesten...) sieht das ganze für mich auch nicht wirklich schön aus. ^^
Ich will nicht behaupten, dass ich das von mir beschriebene Vorgehen schön finde...... aaaber... schöner...

Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 2:46 pm
von fat-lobyte
Xin hat geschrieben:Ich habe mir den Code jetzt mal angeguckt und abgesehen davon dass ich "Variadic Templates" noch nicht kenne (ich muss mir mal 'ne Woche Urlaub nehmen und C++11 mal antesten...) sieht das ganze für mich auch nicht wirklich schön aus. ^^
Ich will nicht behaupten, dass ich das von mir beschriebene Vorgehen schön finde...... aaaber... schöner...

Code? Was für Code? Das war nur ein "mock-up", wie die Anwendung aussehen würde wenns denn funktioniert. Wie würds denn hübscher aussehen?
Aber im Moment laufe ich in so Fehler wie:
gcc-4.6 hat geschrieben:size_sum.cpp:7:67: sorry, unimplemented: cannot expand 'Ts ...' into a fixed-length argument list
Mit Clang funktionierts. Ich glaub ich muss mir wohl oder übel GCC 4.7 aus dem SVN saugen und kompilieren. (Die heizung brauch ich heut wohl nicht einschalten).

Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 2:53 pm
von Xin
fat-lobyte hat geschrieben:Code? Was für Code? Das war nur ein "mock-up", wie die Anwendung aussehen würde wenns denn funktioniert. Wie würds denn hübscher aussehen?
Haarspalter.

Wieso sollte es nicht funktionieren?
Und hübscher wird's nicht mehr - aber ich finde es trotzdem hübscher als die Geschichte.
fat-lobyte hat geschrieben:Aber im Moment laufe ich in so Fehler wie:
gcc-4.6 hat geschrieben:size_sum.cpp:7:67: sorry, unimplemented: cannot expand 'Ts ...' into a fixed-length argument list
Mit Clang funktionierts. Ich glaub ich muss mir wohl oder übel GCC 4.7 aus dem SVN saugen und kompilieren. (Die heizung brauch ich heut wohl nicht einschalten).

Ui, unimplemented ist immer unschön. ^^
Hatte ich auch schonmal bei einem anderen Thema, in der nächsten Version wurde mir dann erklärt, dass es nicht zum Standard gehört.
Aber wirf den funktionierenden Code doch nochmal in die Runde - bin auch neugierig

Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 3:56 pm
von fat-lobyte
So. Also da wär mal was funktionierendes, wobei es noch ein bisschen Roh ist.
Was fehlt:
1) Ein bisschen Zucker: Initialisierung, Kopier/Move-Konstruktor, Destruktoren, ...
2) Ein paar static_asserts, damit Fehler schöner angezeigt werden
3) Was passiert mit nicht-POD-Datentypen?
4) Was passiert mit const/lvalue-ref/rvalue-ref?
Benutzung so:
Code: Alles auswählen
#include <iostream>
#include "packedstruct.hpp"
int main()
{
struct firstmember {};
struct secondmember {};
typedef PackedStruct<
int, firstmember,
double, secondmember
> MyStruct;
std::cout<<"Struct has size: "<<sizeof(MyStruct)<<'\n';
MyStruct s;
s.get<firstmember>() = 5;
std::cout<<"First member was set to: "<<s.get<firstmember>()<<'\n';
s.get<secondmember>() = 3.0;
std::cout<<"First member was set to: "<<s.get<secondmember>()<<'\n';
return 0;
}
Kompilieren selbstverständlich mit "-std=c++11", und geht leider nur mit Clang (nicht G++ 4.6.2, nicht Visual Studio). Bei Gelegenheit werd ichs mit G++ 4.7 nochmal probieren.
Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 4:08 pm
von Xin
Okay, ein char-Array zu casten ist vielleicht nicht die feine englische Art, aber das hat aber doch ganz leicht den Charakter einer Vergewaltigung, oder..?
Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 4:28 pm
von fat-lobyte
Xin hat geschrieben:Okay, ein char-Array zu casten ist vielleicht nicht die feine englische Art, aber das hat aber doch ganz leicht den Charakter einer Vergewaltigung, oder..?
reinterpret_cast<> ist immer eine Vergawaltigung. Aber wo ist das Problem? Ich will meine Variablen in einem ununterbrochenen Speicherbereich speichern, wie sonst soll das gehen?
Außerdem ist es genau das gleiche, was du auch gemacht hast:
Xin hat geschrieben:Code: Alles auswählen
double getB() const { return *static_cast< double * >( &storage[ posOfB ]; ) }
(Wobei ich mich jetzt gerade Frage, warum bei mir der static_cast<>() nicht wollte...)
Re: C++ - Struct Padding/Alignment
Verfasst: Mi Feb 29, 2012 4:45 pm
von Xin
fat-lobyte hat geschrieben:Xin hat geschrieben:Okay, ein char-Array zu casten ist vielleicht nicht die feine englische Art, aber das hat aber doch ganz leicht den Charakter einer Vergewaltigung, oder..?
reinterpret_cast<> ist immer eine Vergawaltigung. Aber wo ist das Problem? Ich will meine Variablen in einem ununterbrochenen Speicherbereich speichern, wie sonst soll das gehen?
Es geht mir nicht um den reinterpret_cast.
Mir geht's um eine Menge schwer zu lesenden Code und besonders um struct firstmember {} und struct secondmember {}. :-/
Das Ganze erscheint mir ein deutlich höheres Fehlerrisiko zu haben, als die Chance, dass (Wert & 1) auf irgendeiner Maschine mal ein anderes Ergebnis liefert. Dass ein char-Array eine Folge hintereinanderliegender Bytes repräsentiert dürfte nicht soweit hergeholt sein und das casten von anderen Datentypen in dieses Array beschreibt eigentlich ganz genau das, was da passiert.
Bist Du sicher, dass Du die richtige Lösung für Dein Problem gefunden hast?