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?
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.
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
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?
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.
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).
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.
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?
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);
}
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.
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.