PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit struct-packing in C


Flyinglosi
2016-01-19, 14:53:01
Hallo Leute,

für die Implementierung einer seriellen Datenübertragung muss ich für ein struct in C die Ausrichtung im Speicher "erzwingen":


#pragma pack(push,1)

typedef struct {
...
struct_inner in;
...
} struct_outer;

#pragma pack(pop)


Der Datentyp struct_inner wird jedoch in einem anderen Header-File deklariert (ohne entsprechende #pragma-Anweisung), weswegen es irgendwann zu einer Zuweisung zwischen zwei Variablen mit scheinbar identem Datentyp aber unterschiedlichem Packing kommt.

z.B.

struct_outer a;
struct_inner b;

a.in=b;


Gibt es eine Möglichkeit eine derartige Zuweisung durchzuführen?

Danke im Vorhinein für eure Antworten

mfg

Stephan

Novum
2016-01-19, 16:52:32
Jede einzelne Variable in den Structs manuell zuweisen. C ist bei solchen Sachen ziemlich antik.

Flyinglosi
2016-01-20, 09:51:58
Das klingt jetzt wenig erfreulich.

Gibt es denn in C eine Möglichkeit durch sämtliche Felder eines structs per for-Schleife zu laufen ohne deren Namen in der entsprechenden Funktion zu kennen?

mfg

Stephan

del_4901
2016-01-20, 14:08:22
Nicht ohne dein eigenes Reflection System aufzubauen. Anfangs wuerde ich einfach eine struct definieren welche nur fuer die serialisierung verwendet wird. Und dann zwischen der intern verwendetten marshalen. Ansonsten fliegt dir das um die Ohren sobald Jemand eine virtuelle funtion oder dergleichen hinzufuegt.

Oid
2016-02-14, 14:56:00
Bist du dir sicher, dass die beiden structs unterschiedlich gepackt werden (ehrliche Frage, ich müsste das selber erst nachprüfen)?

Ein C-Compiler ist ja ziemlich stupide und stur sequenziell. Würde mich wundern, wenn die eine struct_inner, als member von struct_outer, anders gepackt würde als jede andere struct_inner.

Die #pragma-Anweisung könnte sich halt nur auf das Packing der Member von struct_outer auswirken (und nicht auf die "Member der Member").

Stünde ich vor dem Problem, hieße das erstmal Compiler-Manual wälzen und etwas herumprobieren (das offsetof()-Macro könnte dein Freund werden!).

Ganz naiv würde ich erstmal erwarten, dass
a.in=b;
ohne Zutun funktioniert, aber nicht ohne Rückversicherung (bei C weiß man nie) :D


edit:
grad mal ein Testprogramm gehackt:

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

// unpacked size óf this struct: 8 bytes
// packed size of this struct: 7 bytes
typedef struct {
int32_t x;
int8_t y;
// here is one padding byte, if unpacked
int16_t z;
} inner;

// packed struct with an unpacked struct as member
#pragma pack(push,1)
typedef struct {
inner in; // Does this struct have the size of a packed or an unpacked inner struct?
} outer;
#pragma pack(pop)

// struct instances
inner inner_struct;
outer outer_struct;

int main(void)
{
printf("size of inner... %lu\n", sizeof(inner_struct));
printf("size of inner in outer... %lu\n", sizeof(outer_struct.in));

printf("member offsets of inner... x: %lu, y: %lu, z: %lu\n", offsetof(inner,x), offsetof(inner,y), offsetof(inner,z));
printf("member offsets of inner in outer... x: %lu, y: %lu, z: %lu\n", offsetof(outer,in.x), offsetof(outer,in.y), offsetof(outer,in.z));

return 0;
}


Liefert mit gcc auf einer x86-Architektur folgende Ausgabe:

size of inner... 8
size of inner in outer... 8
member offsets of inner... x: 0, y: 4, z: 6
member offsets of inner in outer... x: 0, y: 4, z: 6

Trap
2016-02-14, 16:04:05
für die Implementierung einer seriellen Datenübertragung muss ich für ein struct in C die Ausrichtung im Speicher "erzwingen"
Du könntest die Daten auch einfach in der gewünschten Anordnung in einen Puffer kopieren.

Ist das Übertragungsformat schon festgelegt oder kannst du das frei wählen? Du bist ja nicht der erste der Daten serialisiert, da gibt es einige (https://github.com/protobuf-c/protobuf-c) Bibliotheken (https://github.com/jmckaskill/c-capnproto) zur (https://www.gnu.org/software/libtasn1/) Auswahl (http://libcbor.org/).