Forum: Mikrocontroller und Digitale Elektronik struct aus rohbytes initialisieren


von abc (Gast)


Lesenswert?

Hi,

ich will einen struct von einem 'rohen' byte-array aus initialisieren.
Mit memcpy() geht es, ich frage mich aber wie man das mit
einem Cast macht, das müsste doch auch gehen oder geht das nicht?
1
//global
2
struct Daten {
3
  char msg[200];
4
  long randomvalue;
5
} sensordaten;
6
7
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t laenge) {
8
9
  // jetzt will ich "sensordaten" befüllen
10
  // mit memcpy geht es,statt laenge geht
11
  // auch sizeof(sensordaten)
12
  memcpy(&sensordaten, data, laenge);  
13
14
  // geht das auch mit einer Zuweisung und Typumwandlung
15
  // des uint8_t *daten?
16
  // wie muss ich hier casten?
17
  sensordaten = (??? ) daten;
18
}

PS: Die Code Formatierung funktioniert irgendwie nicht

von Rolf M. (rmagnus)


Lesenswert?

abc schrieb:
> Hi,
>
> ich will einen struct von einem 'rohen' byte-array aus initialisieren.
> Mit memcpy() geht es, ich frage mich aber wie man das mit
> einem Cast macht, das müsste doch auch gehen oder geht das nicht?

Ja. Aber wozu?

> //global
> struct Daten {
>   char msg[200];
>   long randomvalue;
> } sensordaten;
>
> esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t laenge)
> {
>
>   // jetzt will ich "sensordaten" befüllen
>   // mit memcpy geht es,statt laenge geht
>   // auch sizeof(sensordaten)
>   memcpy(&sensordaten, data, laenge);
>
>   // geht das auch mit einer Zuweisung und Typumwandlung
>   // des uint8_t *daten?
>   // wie muss ich hier casten?
>   sensordaten = (??? ) daten;

    sensordaten = *(struct Daten*)data;

Allerdings musst du dann sichersellen, dass das, worauf data zeigt, das 
richtige Alignment hat.

von Jemand (Gast)


Lesenswert?

Rolf M. schrieb:befüllen
>     sensordaten = *(struct Daten*)data;
>
> Allerdings musst du dann sichersellen, dass das, worauf data zeigt, das
> richtige Alignment hat.

Das ist schlicht UB

von abc (Gast)


Lesenswert?

Rolf M. schrieb:
> Ja. Aber wozu?
Da fällt die memcpy() Funktion weg, ein Cast geht doch schneller und 
braucht weniger Speicher oder nicht?

>     sensordaten = *(struct Daten*)data;
Ah 'struct' muss man noch angeben, kein Wunder dass das nie kompilierte.

> Allerdings musst du dann sichersellen, dass das, worauf data zeigt, das
> richtige Alignment hat.
Und wie finde ich das raus?

von mh (Gast)


Lesenswert?

Jemand schrieb:
> Das ist schlicht UB

Hey! Das ist mein Job :/

von Trommler auf Elektroautogalere (Gast)


Lesenswert?

Achso jetzt weiss ich was du meinst. Beim Sender ist der struct mit 
__attribute__((packed)) deklariert, das habe ich hier mal der 
Einfachheit halber weggelassen.

von mh (Gast)


Lesenswert?

Trommler auf Elektroautogalere schrieb:
> Achso jetzt weiss ich was du meinst. Beim Sender ist der struct mit
> __attribute__((packed)) deklariert, das habe ich hier mal der
> Einfachheit halber weggelassen.

Bist du identisch mit abc? An dieser Stelle ist packed erstmal nicht 
relevant.

abc schrieb:
> Rolf M. schrieb:
>> Ja. Aber wozu?
> Da fällt die memcpy() Funktion weg, ein Cast geht doch schneller und
> braucht weniger Speicher oder nicht?
Nein. memcpy wird wegoptimiert, wenn möglich und lohnenswert.

>>     sensordaten = *(struct Daten*)data;
> Ah 'struct' muss man noch angeben, kein Wunder dass das nie kompilierte.
>
>> Allerdings musst du dann sichersellen, dass das, worauf data zeigt, das
>> richtige Alignment hat.
> Und wie finde ich das raus?
Der cast ist illegal, oder in der Sprache des Standards "undefined 
bahavior" (UB).

von Max H. (nilsp)


Lesenswert?

Long Story short: Mache es nicht mit memcpy, oder Pointer Casts (ist 
auch ein memcpy)

Kopiere einfach die Daten Element für Element rüber. Das spart Dir auf 
lange Sicht viel Schmerz. Du musst dich dann um Alignement und den 
Unterschied zwischen C11 bool vs. uint8_t nicht kümmern.

von abc (Gast)


Lesenswert?

Max H. schrieb:
> Unterschied zwischen C11 bool vs. uint8_t nicht kümmern.
Was meinst du damit? Bool gibts schon seit C99. Was ist denn bei C11 
anders und was hat das mit uint8 zu tun?

von Niklas Gürtler (Gast)


Lesenswert?

Und wieder das übliche Problem:
Serialisierung
https://github.com/Erlkoenig90/uSer

von Max H. (nilsp)


Lesenswert?

Tja, das Problem mit dem Cast von Raw-Daten auf Strukturen, die bool 
beinhalten ist, das man 100% sicher sein muss, das dort wirklich nur 
eine 1 oder 0 steht.

Hier ein kleiner Test, der je nach verwendetem Compiler überraschendes 
zu Tage fördert. Beim aktuellen GCC unter Linux kommen z.B. 
unterschiedliche Ergebnisse raus:

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>

typedef struct
{
  bool a;
  bool b;
} myTestStruct;

bool and_function (bool a, bool b)
{
  return a & b;
}

void main (int argc, char **args)
{
  uint8_t rawdata[2] = { 1, 2 };
  assert (sizeof (myTestStruct) == 2);

  // And zweier Bools via Structure Cast:
  myTestStruct * t = (myTestStruct*) rawdata;
  bool result1 = and_function (t->a, t->b);

  // And zweier Bools via element Cast:
  bool a = rawdata[0];
  bool b = rawdata[1];
  bool result2 = a & b;

  // Je nach compiler gibt es hier unterschiedliche Ergebnisse:
  printf ("result2 is %d\n", result2);
  printf ("result1 is %d\n", result1);
}

von mh (Gast)


Lesenswert?

Max H. schrieb:
> myTestStruct * t = (myTestStruct*) rawdata;

Da haben wir ja gleich wieder UB

von Max H. (nilsp)


Lesenswert?

mh schrieb:
> Max H. schrieb:
>> myTestStruct * t = (myTestStruct*) rawdata;
>
> Da haben wir ja gleich wieder UB

Stimmt. Du kannst auch memcpy statt Cast machen. Das ändert nichts an 
dem Problem.

von mh (Gast)


Lesenswert?

Max H. schrieb:
> Stimmt. Du kannst auch memcpy statt Cast machen. Das ändert nichts an
> dem Problem.

Das ändert ne ganze Menge. Mit UB kann der Compiler machen was er will. 
Damit braucht man nicht mehr über andere Laufzeitprobleme reden.

Max H. schrieb:
> Tja, das Problem mit dem Cast von Raw-Daten auf Strukturen, die bool
> beinhalten ist, das man 100% sicher sein muss, das dort wirklich nur
> eine 1 oder 0 steht.
Das ist übrigens nicht vollständig. Man muss sicherstellen, dass die 
Objektrepräsentation übereinstimmt. Genau wie bei allen anderen 
Objekten, die man als Bytes kopiert.

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.