www.mikrocontroller.net

Forum: PC-Programmierung Cast Inkrement problem


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum verwendest Du nicht von vornherein einen BYTE-Pointer?

Autor: Martin L. (melvin_the_moose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>   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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
((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?

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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:
  frame->numNodeIDs   =  *(*(BYTE **)&ptr)++;
  //...
  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:
#define READ_N_INC(p,t) (*(*(t **)&p)++)
  // ...

  frame->numNodeIDs   =  READ_N_INC(ptr, BYTE);
  //...
  frame->dataLen      =  READ_N_INC(ptr, UINT);

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Morin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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).

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.