Struct little endian

OP #7813291

Hallo Leute, ich komme nicht weiter.

Ich empfange hier auf meinem PC ein Packet welches im Payload ein String (Char array enthält, ein INT, FLOAT, BOOL).

1
54 
2
00 00 38 00 2f 40 40 a0 20 08 00 a0 20 08 00 00 
3
66 59 f9 e5 01 00 00 00 10 02 6c 09 a0 00 d3 00 
4
00 00 00 00 00 00 00 00 a6 58 f9 e5 00 00 00 00 
5
16 00 11 03 d3 00 a8 01 d0 00 00 00 ff ff ff ff 
6
ff ff c4 4f 33 0f fe 71 ff ff ff ff ff ff 20 76 
7
7f 18 fe 34 de b1 42 00 dd 31 18 fe 34 04 01 54 
8
48 49 53 20 49 53 20 41 20 43 48 41 52 00 00 00 
9
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 
10
ff 00 00 00 00 59 42 01 00 00 00 3f f1 01 0e

Die Daten werden vom Sender und Empfänger 1:1 aufgebaut:

1
typedef struct struct_message 
2
{
3
    uint8_t header[95];
4
    char a[32]; 
5
    int b;
6
    float c;
7
    bool d;
8
} struct_message;
9

10
struct_message myData;

Damit ich den Anfang erwische, habe ich den Header als Dummy im Struct angelegt (uint8_t header[95];).

Auf der Empgfängerseite kopiere ich mir das mit memcpy in das Struct. Soweit so gut, die Zeichenkette wird korrekt ausgegeben aber INT, FLOAT,BOOL nicht. Die Werte scheinen als little Endian abgelegt.

Wie gehe ich damit um?

1
    memcpy(&myData, data, sizeof(myData));
2

3
                        printf("char:%s\n", myData.a);
4
                        printf("int:%d\n", myData.b);
5
                        printf("float:%f\n", myData.c);
6
                        printf("bool:%d\n", myData.d);

Auf der Senderseite werden die Daten wie folgt erzeugt:

1
    // Set values to send
2
    strcpy(myData.a, "THIS IS A CHAR");
3
    myData.b = 65535;
4
    myData.c = 54.25;
5
    myData.d = true;

Auf dem Bild im Anhang ist das Char Array markiert, die Nullen nach den Werten entsprechen (char a[32]) den 32 byte. Danach steht der INT Wert (65535) in Hex FF FF, dann Float (54.25) in Hex 00 00 59 42. Zum schluss Bool (1) in Hex 01. Alles 4 byte lang.

Angehängte Dateien:

Wenn Du bei einem int statt 0xffff empfängerseitig 0xff rausbekommst, klingt das nicht nach einem Endianness-Problem (dann wäre es 0xffff0000), sondern nach einem Alignment-Problem.

Dein header[95] schreit geradezu danach.

OP

J. S. schrieb:

Gib doch mal ein sizeof(myData) aus. Debugger hilft auch…

Mach ich ...

1
-------------------------------------------------------------------------
2

3
00 00 38 00 2f 40 40 a0 20 08 00 a0 20 08 00 00 
4
cf 1f 18 dd 02 00 00 00 10 02 6c 09 a0 00 d3 00 
5
00 00 00 00 00 00 00 00 0f 1f 18 dd 00 00 00 00 
6
16 00 11 03 d3 00 a7 01 d0 00 00 00 ff ff ff ff 
7
ff ff c4 4f 33 0f fe 71 ff ff ff ff ff ff 40 79 
8
7f 18 fe 34 18 b8 5f c2 dd 31 18 fe 34 04 01 54 
9
48 49 53 20 49 53 20 41 20 43 48 41 52 00 00 00 
10
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 
11
ff 00 00 00 00 59 42 01 00 00 00 1b 60 f5 a6 
12
-------------------------------------------------------------------------
13

14
Packet length:143
15
myData:140
16
char:THIS IS A CHAR
17
int:255
18
float:0.000000
19
bool:0
OP

J. S. schrieb:

140 passt nicht, alignment problem. Auf 1 Byte alignment stellen für die Struktur, das ist Compilerabhängig.

Hallo Jojos, wie macht man das?

Ich habe letzens bei meiner Streifzügen das hier gefunden: attribute((packed))

1
typedef struct struct_message 
2
{
3
    uint8_t header[93];
4
    char a[32]; 
5
    int b;
6
    float c;
7
    bool d;
8
} __attribute__((aligned(4))) struct_message;

Wenn ich das benutze bekomme ich:

1
Packet length:140
2
Packet length:140
3
myData:140
4
char:THIS IS A CHAR
5
int:255
6
float:0.000000
7
bool:123

???

Welle 🧐 S. schrieb:

Auf der Senderseite werden die Daten wie folgt erzeugt

Ist das in Stein gemeisselt, oder kannst Du aus dem 95-Byte-Header auch einen mit 96 Bytes machen?

Sich nicht an das Alignment zu halten, sorgt je nach Plattform für schlechtere Performance (z.B. x86), weil aus einem Speicherzugriff zwei werden, oder knallt sogar (z.B. m68k).

OP

J. S. schrieb:

140 passt nicht, alignment problem. Auf 1 Byte alignment stellen für die Struktur, das ist Compilerabhängig.

Ok, habe ich gemacht ...

1
typedef struct struct_message 
2
{
3
    uint8_t header[93];     // 2 Byte
4
    char a[32];             // 2 Byte
5
    int b;                  // 4 Byte
6
    float c;                // 4 byte
7
    bool d;                 // 4 Byte
8
}__attribute__((packed, aligned(1))) struct_message; struct_message myData;

https://stackoverflow.com/questions/11770451/what-is-the-meaning-of-attribute-packed-aligned4

https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html

Aber kein Erfolg:

1
Packet length:143
2
Struct size of myData:140
3
Struct size of myTest:8
4
char:THIS IS A CHAR
5
int:39
6
float:0.000000
7
bool:0

MyTest war ein Test:

1
typedef struct teststruct
2
{
3
     char Data1;
4
     int Data2;
5
     unsigned short Data3;
6
     char Data4;
7

8
}__attribute__((packed, aligned(1))) teststruct; teststruct myTest;

Hmm ...

OP

ENTWARNUNG! Ich habe nochmal die Packete (Wshark) durchgezählt ...

Siehe da:

1
typedef struct struct_message 
2
{
3
    uint8_t header[56];       // 2 Byte
4
    uint8_t action[24];       // 2 Byte
5
    uint8_t vendor[1];        // 2 Byte
6
    uint8_t oui[3];           // 2 Byte
7
    uint8_t noidea[11];       // 2 Byte
8
    char a[32];               // 2 Byte
9
    int b;                    // 4 Byte
10
    float c;                  // 4 byte
11
    bool d;                   // 4 Byte
12
}__attribute__((packed, aligned(1))) struct_message; struct_message myData;
1
Packet length:143
2
Struct size of myData:136
3
char:THIS IS A CHAR
4
int:9999
5
float:54.250000
6
bool:1

Bingo!

Die headersize stimmt noch nicht. Der Header ist doch im Espressif IDK definiert. Das mit der String Ausgabe ist keine sichere Methode den Anfang zu finden, da sind zwei nicht druckbare Zeichen vor die du auch treffen kannst. Also printf("%x/n", myData[0]);

Und wieso ständig andere Strukturen? Da blickt doch keiner mehr durch.

OP

Ich habe jetzt aus faulheit die Radiotapdaten rausgepopelt. Spannend ist, am Ende das FCS Packet. Das muss ich mir noch erarbeiten.

1
typedef struct struct_message 
2
{
3
  uint8_t radio_tap_header[95];
4
  int b;
5
  float c;
6
  bool d;
7
  uint8_t pad_for_bool[3];
8
  float e;
9
  int fcs;
10
}__attribute__((packed, aligned(1))) struct_message; 
11
struct_message myData;
12

13
    
14
void print_packet(uint8_t *data, int len)
15
{ 
16
  memcpy(&myData, data, len);  
17

18
    printf("packet laenge: %d\n",len);
19
    printf("sizeof(myData): %ld\n",sizeof(myData));
20
    printf("antenna signal:%d\n", myData.radio_tap_header[30]);
21
    printf("int:%d\n", myData.b);
22
    printf("float:%.3f\n", myData.c); 
23
    printf("bool:%d\n", myData.d);
24
    printf("float:%.3f\n", myData.e);
25

26
printf("\n");
27
}
OP

Welle 🧐 S. schrieb:

1
> typedef struct struct_message
2
> {
3
>     uint8_t header[56];       // 2 Byte
4
>     uint8_t action[24];       // 2 Byte
5
>     uint8_t vendor[1];        // 2 Byte
6
>     uint8_t oui[3];           // 2 Byte
7
>     uint8_t noidea[11];       // 2 Byte
8
>     char a[32];               // 2 Byte
9
>     int b;                    // 4 Byte
10
>     float c;                  // 4 byte
11
>     bool d;                   // 4 Byte
12
> }__attribute__((packed, aligned(1))) struct_message; struct_message 
13
> myData;
14
>

Falls das hier mal jemand findet, BOOL ist nur EIN Byte und muss mit einem Pad[3] aufgefüllt werden ... es hatt nur funktioniert weil es am Ende stand.

Welle 🧐 S. schrieb:

Falls das hier mal jemand findet, BOOL ist nur EIN Byte und muss mit einem Pad[3] aufgefüllt werden ... es hatt nur funktioniert weil es am Ende stand.

Aber das weiß man doch. Das ist doch schon seit Jahrzehnten so. Spätestens mit der breiten Einführung dem M68000 Mitte der 80er wurde das so gemacht.

"68000 und 68010 können nur byteweise auf ungerade Adressen zugreifen. Diese Exception wird ausgelöst, wenn man dennoch einen Wort- oder Langwort-Zugriff versucht (auch Programmzähler oder Stack-Pointer dürfen keine ungeraden Adressen enthalten)." https://freemint.github.io/tos.hyp/de/the_system_vectors.html

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über ein Jahr alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.