hallo, ich wollte einen DatenStrom den ich aus einem EEProm lese folgendermaßen verarbeiten: void* ptr = ((void*)data); frame->numNodeIDs = ((BYTE*)ptr)++; frame->nodes = ((BYTE*)ptr)++; frame->cmdClass = ((BYTE*)ptr)++; frame->cmd = ((BYTE*)ptr)++; frame->dataLen = ((UINT*)ptr)++; frame->data = ((BYTE*)ptr)++; aber der compiler meint expression must be a modifiable lvalue. leuchtet mir nicht ein warum es nicht so gehen sollte denn ptr ist doch nicht const oder so was? Gruß flow
> void* ptr = ((void*)data); > > frame->numNodeIDs = ((BYTE*)ptr)++; > ... ++ ist ein Operator, der auf eine Variable (lvalue) angewandt werden muß. ((BYTE*)ptr) ist aber ein Zwischenrechenergebnis. Der nächste Schritt wäre, ((BYTE*)ptr++); zu schreiben. Aber ich fürchte (bin aber nicht sicher...), daß das auch nicht geht, weil ptr ein void pointer ist. Für die Zeigerarithmetik ptr++ müßte die Größe des Datentyps bekannt sein, auf den ptr zeigt. Aber was ist sizeof(void) (0 oder was?)? Gruß Martin
((BYTE*)ptr) gibt dir einen r-value vom Typ BYTE*, aber ++ verlangt einen l-value. In C++ kannst du schreiben ((BYTE*&)ptr)++; Oder in C (evtl., das ist ungetestet): (*(BYTE**)ptr)++; Aber ich schliesse mich Rufus an: Wieso machst du das so umstaendlich?
> Warum verwendest Du nicht von vornherein einen BYTE-Pointer? Er möchte offensichtlich aus dem Array nicht nur BYTE-, sondern auch UINT-Werte auslesen. Bei letzteren muss ptr um 4 statt um 1 erhöht werden. Wenn man Lesen und Inkrementieren in einen Ausdruck pressen will kommen solche seltsamen Konstrukte zustande. > (*(BYTE**)ptr)++; Genau so geht's, nur das & vor ptr fehlt:
1 | frame->numNodeIDs = *(*(BYTE **)&ptr)++; |
2 | //...
|
3 | frame->dataLen = *(*(UINT **)&ptr)++; |
Eine gecastete Variable ist kein lvalue, ein dereferenzierter gecasteter Pointer hingegen schon. Das ist der Trick bei der Sache. Damit das Ganze nicht so wüst aussieht, kannst du es in ein Makro packen:
1 | #define READ_N_INC(p,t) (*(*(t **)&p)++)
|
2 | // ...
|
3 | |
4 | frame->numNodeIDs = READ_N_INC(ptr, BYTE); |
5 | //...
|
6 | frame->dataLen = READ_N_INC(ptr, UINT); |
> frame->numNodeIDs = ((BYTE*)ptr)++; Im Prinzip gibt dir der Cast eine Kopie von ptr vom TYP BYTE* zurück. Diese Kopie versuchst du zu inkrementieren. Da sie nur ein temporärer Zwischenwert ist, der nicht modifizierbar ist, meldet der Compiler einen Fehler. Wenn das gehen würde, hätte es aber eh nicht den gewünschten Effekt, da ptr unverändert bliebe. > frame->dataLen = *(*(UINT **)&ptr)++; Eine andere Möglichkeit, wenn man ptr als BYTE* definiert und nicht alles in einen einzelnen Audsruck quetscht: frame->dataLen = (UINT*)ptr; ptr += sizeof(UINT); Für die ganzen anderen Einträge, bei denen eh ein BYTE* verlangt wird, kann man sich das Ganze dann auch gleich schenken.
Hallo, sry für die späte antwort... Aber vielen Dank für die sehr guten und schnellen antworten. hat wunderbar geklappt und hab wieder ein bischen mehr ahnung ;) Gruß
Rolf Magnus wrote: >> frame->dataLen = *(*(UINT **)&ptr)++; Hier verstehe ich, warum es Leute gibt, die sagen das die Sprache C/C++ einfach Müll ist. Weil man eben solche Ausdrücke erzeugen kann. Bin gespannt ob der Programmierer die selber nach einem Jahr oder später selber noch versteht. Unleserlicher geht es kaum noch. > frame->dataLen = (UINT*)ptr; ptr += sizeof(UINT); Das ist die einzige Lösung, die akzeptabel ist.
> Hier verstehe ich, warum es Leute gibt, die sagen das die Sprache C/C++ > einfach Müll ist. Weil man eben solche Ausdrücke erzeugen kann. Man kann in jeder Programmiersprache schwer verständlichen Code schreiben.
Rolf Magnus wrote: >> Hier verstehe ich, warum es Leute gibt, die sagen das die Sprache C/C++ >> einfach Müll ist. Weil man eben solche Ausdrücke erzeugen kann. > > Man kann in jeder Programmiersprache schwer verständlichen Code > schreiben. Das stimmt. Allerdings in C/C++ auch zusätzlich noch sehr kryptisch (s.o.). Das hat mit gutem Programmierstil nichts mehr zu tun.
900ss D. wrote: > Rolf Magnus wrote: >>> Hier verstehe ich, warum es Leute gibt, die sagen das die Sprache C/C++ >>> einfach Müll ist. Weil man eben solche Ausdrücke erzeugen kann. >> >> Man kann in jeder Programmiersprache schwer verständlichen Code >> schreiben. > Das stimmt. Allerdings in C/C++ auch zusätzlich noch sehr kryptisch > (s.o.). Das hat mit gutem Programmierstil nichts mehr zu tun. Stimme ich dir zu. Die Schlussfolgerung kann aber eigentlich nur lauten: Da zäumt jemand ein Pferd mit dem falschen Werkzeug auf. Anstatt diesen ganzen castings eine Struktur definieren, die Struktur mit einer Union über den Bytebuffer legen und schon verschwindet das Problem ganz von alleine. Oder aber gleich aus dem EEPROM in eine derartige Struktur variable einlesen und auch dann ist das Problem ganz von alleine aus der Welt. Manchmal sind casts notwendig. Wenn man aber exzessiv casten muss um ein Problem zu lösen, sollte man mal einen Schritt zurücktreten und sich überlegen, ob man im Moment mit den ganzen Casts nicht das falsche Problem unter den Casts versteckt.
> Anstatt diesen ganzen castings eine Struktur definieren, > die Struktur mit einer Union über den Bytebuffer legen > und schon verschwindet das Problem ganz von alleine. Wie würdest du das denn machen? Per union zwei Datentypen "übereinanderlegen" ist klar, aber wie würdest du die Struktur hinter dem Pointer in einem C Datentyp ausdrücken? Dafür gibt es in C keinen Datentyp (es wird zwar immer wieder fälschlich behauptet, struct-Typen wären dafür gut, aber bei denen fügt der Compiler Füllbytes ein, unter anderem um 32-bit-Variablen zu alignen, und dann stimmen sie nicht mehr mit der tatsächlichen Struktur der Daten überein).
> aber bei denen fügt der Compiler Füllbytes ein
... wenn man es denn nicht abschaltet, was je nach Compiler mit
verschiedenen #pragmas erfolgen kann.
Und dann kann so eine Struktur sehr wohl funktionieren.
Allerdings muss man sich dann als Programmierer auch damit
auseinandersetzen, wie die verwendete Hardware auf Zugriffe auf nicht
korrekt ausgerichtete Objekte verhält; nicht alle Prozessoren sind da so
nachsichtig wie 32-Bit x86.
>> aber bei denen fügt der Compiler Füllbytes ein > > ... wenn man es denn nicht abschaltet, was je nach Compiler mit > verschiedenen #pragmas erfolgen kann. Ein Programm, dessen Funktion von solchen #pragmas abhängt, ist aber in meinen Augen kein richtiges C-Programm mehr, da es stark compiler- und hardwareabhängig ist. Der Trick mit den Pointern (egal, ob die kryptische oder weniger kryptische Variante genommen wird) ist wenigstens nur hardwareabhängig. Die einzig wirklich saubere Lösung wäre es, die Werte mittels Shift- und Oder-Operationen zusammenzusetzen.
yalu wrote: >>> aber bei denen fügt der Compiler Füllbytes ein >> >> ... wenn man es denn nicht abschaltet, was je nach Compiler mit >> verschiedenen #pragmas erfolgen kann. > > Ein Programm, dessen Funktion von solchen #pragmas abhängt, ist aber > in meinen Augen kein richtiges C-Programm mehr, da es stark compiler- > und hardwareabhängig ist. Über einen Punkt, denke ich, gibt es hier soweiso keine Dikussion: Derartige Umbiegereien hat man lediglich an den I/O Schnittstellen eines Programmes. Sprich dort, wo ein externes System irgendwie an den großen Rest eines Programmes angebunden ist. An diesen Stellen hab zumindest ich absolut kein Problem damit, wenn das hardware/compilerabhängig ist. Das ist für mich in Ordnung und ist mir eigentlich lieber als diese Casting Orgien :-) Soooo oft wechsle ich nun auch wieder nicht den Compiler. > Die einzig wirklich saubere Lösung wäre es, die Werte mittels Shift- > und Oder-Operationen zusammenzusetzen. Da hast du allerdings recht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.