Zero-size Array in struct
-
zero-sized arrays != flexible array members?
Beides in C++ illegal?
-
Da wir hier im C++-Bereich sind sage ich einfach mal std::vector
-
Leider ist der char array vorgegeben, also diesen empfange ich so per Netzwerk. Mit Hilfe von struct's lassen sich die Daten danach recht einfach verarbeiten ohne großen Aufwand.
-
"Nicht richtig" - das beschreibt es ja sehr genau.
Wer weiß, ob das array überhaupt korrekte Daten enthält.
-
In dem Fall ist das ein von mir erzeugtes Array zum testen und da müsste GruppaA und GruppeB stehen.
-
auto liste = *(struct LIST*)msg;
muss natürlich
auto liste = (struct LIST*)msg;
sein und entsprechend mit pointern gearbeitet werden.
-
Und statt char muss msg unsigned char sein.
-
Danke dir, nun geht es
-
MrSpoocy schrieb:
Danke dir, nun geht es
Und verstehst du auch, warum?
-
Ehrlich gesagt nicht ganz, ich dachte mir schon das SubListe ein Pointer sein wird und habe wilde dinge wie
auto sublist = (struct SubLists)&liste.subLists[0];
versucht. Aber alles wollte nicht so ganz klappen.
-
Dein Problem war, dass du in der Zeile
auto liste = *(struct LIST*)msg;
eine Kopie deines Structs machst, da du nach dem Cast dereferenzierst. Der Compiler muss also dein Objekt kopieren, aber da du Zero Length Arrays in deinem Struct hast (übrigens kein Feature, dass es laut Standard gibt) kann der Compiler überhaupt nicht wissen wie viele Bytes er kopieren muss. Deine subList enthält also Müll. Wenn du aber in dieser Zeile nicht dereferenzierst speicherst du dir nur einen Pointer und das ist OK.
Die unsigned char Geschichte ist übrigens nicht notwendig. Ohne gibts zwar ein paar Warnungen, aber die Werte werden trotzdem richtig konvertiert.
Irgendwie ist dein Code auch ein sehr merkwürdiger Mix zwischen C und C++. Erstmal ist das Konstrukt
typedef struct {/* stuff */} LIST;
typisch C, um nicht überall einstruct
vorLIST
schreiben zu müssen. Du schreibst es aber trotzdem noch davor. In C++ ist weder das typedef noch struct überall nötig. Außerdem sollte man sich angewöhnen einen der C++ Casts zu nutzen, statt den C Cast, der einfach alles castet was man ihm vorwirft. So würde dann die C++ Variante deines Codes aussehen:struct SubLists { unsigned int id; char name[14]; }; struct LIST { unsigned short ListeType; unsigned short ListLength; int id; char name[8]; SubLists subLists[]; }; int main() { unsigned char msg[] = { 0x12, 0x00, 0x34, 0x00, 0xA8, 0x22, 0x00, 0x00, 0x54, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x23, 0x00, 0x00, 0x47, 0x72, 0x75, 0x70, 0x70, 0x65, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x27, 0x00, 0x00, 0x47, 0x72, 0x75, 0x70, 0x70, 0x65, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; auto liste = reinterpret_cast<LIST*>(msg); std::cout << "Name: " << liste->name << "\n"; std::cout << "SubName: " << liste->subLists[0].name << "\n"; }
-
MrSpoocy schrieb:
Ehrlich gesagt nicht ganz, ich dachte mir schon das SubListe ein Pointer sein wird und habe wilde dinge wie
auto sublist = (struct SubLists)&liste.subLists[0];
versucht. Aber alles wollte nicht so ganz klappen.
Wie wäre es denn die
subLists
aus demLIST
-Struct herauszunemen und einfach zwei Pointer zu verwenden. Z.B. EinenListHead*
, den du auf den Anfang deinesmsg
-Arrays abbildest, und einSubLists*
der auf den Unterlisten-Teil desmsg
-Arrays zeigt, sofern dieser vorhanden ist (ich vermute mal wennListLength > 0
, oder?). Wenn keine Sublists vorhanden sind, dann kann ist der Sublists-Pointer ebennullptr
. Die beiden Pointer kann man dann auch wieder schn in einer "eigentlichen"List
-Klasse zusammenfassen und so die innereien wegabstrahieren. Ungefähr so oder ähnlich:struct List { struct SubList { unsigned int id; char name[14]; }; struct Head { unsigned short ListeType; unsigned short ListLength; int id; char name[8]; }; Head* head; SubList* subLists; inline List(char* msg) : head(reinterpret_cast<Head*>(msg)), subList(nullptr) { if (head != nullptr && head->ListLength > 0) subLists = reinterpret_cast<SubList*>(msg + sizeof(head)); } };
Instanzen von
List
, bzw. deren Unterklassen sind natürlich auch hier nur übermsg
"drübergelegt", d.h.msg
sollte mindestens so lange leben, wie es eineList
-Instanz tut.Finnegan
P.S.: Mit meinem Ansatz Versuche ich das meines erachtens hauptsächliche Problem zu lösen, dass Struct-Member-Arrays eine feste Länge > 0 haben müssen, die scheinbar anderen Probleme die es da noch gab/gibt hab ich mir nicht genau ansgesehen
P.P.S: Beim "draufmappen" von Structs auf irgendwelche Byte-Daten muss man natürlich eventuell noch eine Reihe Details beachten, z.B. dass das Struct auch wirklich "passt und bündig ist", falls der Compiler meint da z.B. noch irgendwelches Padding und Alignment machen zu müssen. Eventuell benötigt man da noch irgenwelche Compiler-spezifischen Sachen (#pragma pack()
et al.). Auch muss man eventuell bei so einemunsigned int
in dem Struct die Endianess anpassen, je nachdem was da für Daten reinkommen (vielleicht von einem System mit anderer Endianess ohne dass das Protokoll sich auf eine von beiden festlegt).