Forum: PC-Programmierung Struct little endian


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Welle 🧐 S. (w3llschmidt)


Angehängte Dateien:

Lesenswert?

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.

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

Das sollte passen, aber das alignment wird dir den krummen Start nach 95 
Byte verschieben.

von Daniel G. (denial)


Lesenswert?

Du schreibst dir kleine Funktionen, die die Bytes tauschen. POSIX 
definiert dafür die Funktionen htonl, htons, ntohl und ntohs, die 
zwischen der Endianess der CPU und Big Endian konvertieren.

von Hmmm (hmmm)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

Neben big/little endian gäbs auch noch das Stichwörter alignment, dazu 
packed.

Wenn’s aber wirklich an der Endianess liegt, gibts per Google oder 
ChatGPT Hilfe, wie man die Werte umwandelt.

Oliver

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Vielen Dank, für eure Tips.

Wenn das Alignment nicht stimmen würde, würde das Char Array nicht 
rauskommen, oder?

von Hmmm (hmmm)


Lesenswert?

Welle 🧐 S. schrieb:
> Wenn das Alignment nicht stimmen würde, würde das Char Array nicht
> rauskommen, oder?

Doch, dafür gilt normalerweise 1-Byte-Alignment, also im Endeffekt 
keines.

Das Problem beginnt beim int mit 4-Byte-Alignment.

von J. S. (jojos)


Lesenswert?

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

: Bearbeitet durch User
von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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

von J. S. (jojos)


Lesenswert?

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

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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

???

: Bearbeitet durch User
von Hmmm (hmmm)


Lesenswert?

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).

von Oliver S. (oliverso)


Lesenswert?

Hmmm schrieb:
> Welle 🧐 S. schrieb:
>> Auf der Senderseite werden die Daten wie folgt erzeugt
>
> Ist das in Stein gemeisselt

Eigentlich müsste die Frage: woher du wissen, junger Padavan?

Oliver

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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 ...

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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!

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

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.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Welle 🧐 S. schrieb:
> uint8_t header[56];       // 2 Byte
>     uint8_t action[24];       // 2 Byte
>     uint8_t vendor[1];        // 2 Byte
>     uint8_t oui[3];           // 2 Byte
>     uint8_t noidea[11];       // 2 Byte
>     char a[32];               // 2 Byte


Endlich mal klare Kommentare im src ;-)

scnr,
WK

von J. S. (jojos)


Lesenswert?

Na Glückwunsch, trotzdem ist es besser den richtigen Header zu 
verwenden. Da stecken auch interessante Sachen wie RSSI Werte drin.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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
}

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

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.

: Bearbeitet durch User
von Peter (pittyj)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.