struct aus rohbytes initialisieren

Gast #6432386
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
#6432397
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.
Gast #6432411
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?
Gast #6432428
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).
#6432470
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.
#6432867
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);
}
Gast #6433004
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren