Hallo,
da ich in einem Byte-Stream einzelne Nibble auswerten möchte wollte ich
dieses Makro schreiben aber leider mag er es nicht!! kann mir jemand
sagen wo der Fehler zu finden ist?
#define NIBL2NIBL( SOURCEBYTE , DESTBYTE ) \
( \
((BYTE)_DESTBYTE_) |= 0x0F ;\
((BYTE)_DESTBYTE_) ^= ~0x0F ;\
((BYTE)_DESTBYTE_) |= (SOURCEBYTE & 0x0F) \
)
Gruß
Hi,
danke für die schnelle Antwort aber ich bekomme in IAR noch folgende
Fehlermeldungen. (haben sich auch nicht geändert):
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe018]: expected a ")"
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe065]: expected a ";"
der Code dazu sieht so aus (nur zum testen natürlich):
BYTE a, b;
a = 0xFA;
b = 0xF5;
NIBL2NIBL( a, b );
Da verstehe ich nicht, was Du erreichen willst.
Das Makro macht Unterstriche an die Werte (warum?), und in der letzten
Makrozeile fehlt das Semikolon.
Willst Du:
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE) \
( \
((BYTE)(DESTBYTE)) |= 0x0F ;\
((BYTE)(DESTBYTE)) ^= ~0x0F ;\
((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F) ;\
)
1. Zeile: alle Bits in Low-Nibble werden auf 1 gesetzt
2. Zeile: alle Bits werden im Low-Nibble auf 0 gesetzt
3. Zeile: "Kopieren" des SourceLowNibble zum DestLowNibble
die ersten zwei Zeilen sind deswegen nötig um zu garantieren das das
DestLowNibble wirklich 0 ist und nicht vordefiniert ist, denn da in der
dritten Zeile ein Veroderung vorgenommen wird ist es möglich das "alte
Bits" mitgeschleppt werden.
Gruß
Flo
noch zur anderen Antwort...
die unterstrich nur deswegen damit ich garantieren kann das niemand evtl
eine Variable namens DESTBYTE benutzt deswegen DESTBYTE.
Das Semikolon deswegen nicht damit ich es wie eine normale C-Anweisung
mit ; abschließen kann (sonst würde ja doppelt ; da stehen)
Ach, das mit den Unterstrichen habe ich nicht richtig gesehen, weil Du
den Code nicht als C-Code eingefügt hattest.....(siehe erster Post...).
[edit] Ohne Semikolon ist o.k., aber dann darf danach keine Klammer
kommen...
Ok stimmt ist richtig....
leider kommen immernoch die Fehlermeldungen
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe018]: expected a ")"
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe029]: expected an expression
Wie sieht '*genau*' dein Makro jetzt aus?
Wie verwendest du es, ebenfalls '*genau*'?
Die Sache mit den Unterstrichen ist Unsinn. Im ganzen
Programm gibt es keine Variable namens DESTBYTE.
Ein Makro macht einfach nur eine Textsubstitution.
Im Source wird der Quelltext
NIBL2NIBL( a, b );
durch den im Makro angegebenen Text ersetzt. Um also die
Fehlermeldungen deuten zu können, muß man den exakten
Text bei der Verwendung des Makros kennen, den exakten
Makrotext und erst dann kann man sich darüber Gedanken machen
welcher neue Text durch die Makrosubstitution entsteht und warum
der Copiler hier Fehler meldet.
Habe ein neues Project gestartet und das ist jetzt alles was drin ist
mit folgenden Fehlermeldungen....
#define BYTE char
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE) \
( \
((BYTE)(DESTBYTE)) &= 0xF0 ;\
((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F) ;\
)
int main()
{
BYTE a, b;
a = 0xFE;
b = 0xFB;
NIBL2NIBL( a, b );
return 0;
}
Building configuration: MakroTest - Debug
Updating build tree...
main.c
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe018]: expected a ")"
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe029]: expected an expression
Total number of errors: 4
Total number of warnings: 0
Building configuration: MakroTest - Debug
Updating build tree...
main.c
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe137]: expression must be a modifiable lvalue
Total number of errors: 2
Total number of warnings: 0
Kann man machen.
Aber der Fehler besteht darin, dass er ( anstatt { verwendet
hat.
Also: runde Klammern anstatt geschwungenen Klammern.
Das Makro muss lauten
1
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE) \
2
{ \
3
((BYTE)(DESTBYTE)) &= 0xF0 ;\
4
((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F) ;\
5
}
PS: Für einen Datentyp Byte sollte man immer unsigned char
verwenden und nicht einfach nur char. Bei einem char ist
nicht sichergestellt ob der jetzt mit oder ohne Vorzeichen
gewertet wird.
OK habs jetzt hinbekommen so funktionierts:
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE){ \
(DESTBYTE) &= 0xF0 ;\
(DESTBYTE) |= ((SOURCEBYTE) & 0x0F);\
}
aber mich würde interessieren warum ich den Cast weglassen muss?
schon mal vielen lieben Dank für eure schnelle Hilfe...
Gruß
Flo
Ist auch nicht unbedingt gut....
Dann kriegt man nach Makroauflösung;
1
{
2
((BYTE)(b))&=0xF0;
3
((BYTE)(b))|=((a)&0x0F);
4
};
Und nicht alle Compiler mögen das Semikolon an der Stelle (ist es da
überhaupt erlaubt?).
Deshalb würde ich lieber die Klammern ganz weglassen, da keine lokalen
Variablen benötigt werden muß man auch keinen Block bilden...
Zweimal editiert, um das Makro richtig aufzulösen ;-)
@Bernhard
habe deinen Vorschlag erst gelesen nachdem ich meinen Post gesetzt
hab...
leider bringt er aber bei deinem immernoch die Fehlermeldung...
und danke für den Tip mit dem unsigned char
Ein Ausdruck mit einem typecast ist kein lvalue, genau das besagt
letztlich die Fehlermeldung. Die linke Seite einer Zuweisung darf
folglich keinen typecast enthalten.
(GCC hat das früher mal toleriert, seit Version 4 aber auch nicht
mehr.)
Jetzt dämmerts mir...
Eigentlich darf mann keine lvalues casten (also kein cast auf der linken
Seite der Zuweisung), wenns auch einige Compiler erlauben....
Typischerweise ist die Fehlermeldung alles andere als hilfreich...
> 1. Zeile: alle Bits in Low-Nibble werden auf 1 gesetzt> 2. Zeile: alle Bits werden im Low-Nibble auf 0 gesetzt
"Bit-Clear" ist das gleiche wie AND-NOT, aber das hast du später wohl
auch bemerkt.
> Das Semikolon deswegen nicht damit ich es wie eine normale C-Anweisung> mit ; abschließen kann (sonst würde ja doppelt ; da stehen)
Im Gegensatz zu manchen anderen Sprachen sind bei C leere Statements
möglich, d.h. du könntes auch hunderte von Semikolons hintereinander
haben und der Compiler sollte sich nicht daran stören.
Wie Karl Heinz richtig angemerkt hat, sollte das Makro in einen eigenen
Block, also in geschweiften Klammern stehen.
Wenn du es in runde Klammern setzt ist es ein Ausdruck und darin sind
die durch Semikolon abgeschlossenen Statements nicht erlaubt.
Bernhard M. wrote:
> Typischerweise ist die Fehlermeldung alles andere als hilfreich.
Fand ich gar nicht. Ich hab's nur durch die Fehlermeldung geschnallt,
was daran foul war.
Jörg Wunsch wrote:
> Bernhard M. wrote:>>> Typischerweise ist die Fehlermeldung alles andere als hilfreich.>> Fand ich gar nicht. Ich hab's nur durch die Fehlermeldung geschnallt,> was daran foul war.
:-)
Muss gestehen: Ich nicht.
Ich hab rumgerätselt warum er denn den lvalue anmeckert. Ein
kurzer Test mit VC++ brachte mich auch nicht weiter.
Als du dann den cast ins Spiel brachtest, viel es wie Schuppen
von den Haaren.
Ich gebe zu, dass ich durch die kürzlich erfolgte GCC-Änderung in
diesem Bereich das Thema noch einigermaßen im Hinterkopf hatte.
Irgendwo hatten wir auch noch typecasts auf der linken Seite
rumgeistern in hysterischem Code...
Na ja, das mit der Fehlermeldung des Compilers ist so eine Sache...
Ich weiß aus eigener Erfahrung wie schwierig es ist, verständliche
Fehlermeldungen zu erzeugen, die auch jemanden helfen, der nicht so in
der Materie (der jew. Applikation) steckt....
Error[Pe137]: expression must be a modifiable lvalue
Error[Pe018]: expected a ")"
Hier kam in der Fehlermeldung doch überhaupt kein Hinweis auf den Cast,
somit geht der unbedarfte Anwender erst mal davon aus, daß mit dem
lvalue die Variable gemeint ist (er sagt einem ja nicht, welche
"expression" er meint)...
Mit die besten Fehlermeldung haben meiner Meinung nach die C++ Compiler
von HP, da sie seit einigen Jahren auch Hinweise geben, was falsch sein
könnte.
Z.B. finden sie bei dem typischen Tippfehler im Variablennamen
üblicherweise die Variable, die man eigentlich gemeint hat, und weisen
darauf hin.
Problematisch für Fehlermeldungen eines Compilers ist, dass er
den Quelltext ja bereits in einen Syntaxbaum zerlegt hat an dieser
Stelle. Damit hat er für die linke Seite nur noch einen Ausdruck
mit einem Wert und die Tatsache, dass dieser Ausdruck keinen lvalue
darstellt. Dass dies wiederum durch den typecast erfolgt war, hat
er u. U. einfach bereits "vergessen" an dieser Stelle.
Man kann auch die linke Seite casten, muß es aber indirekt über einen
Pointer machen.
Man ist dann aber selbst dafür verantwortlich, daß es sich um Typen im
gleichen Byteformat handelt.
Also ein char nach int geht nicht.
Aber ein nicht volatile nach volatile oder ein signed nach unsigned
casten geht.
Peter
Apropo casten...
was hat das ganze eigentlich mit den Präprozessor casten auf sich??
(wenn man das so bezeichnen kann...)
also unterschied zwischen
#define 4
#define 4u
#define 4l
hab noch keine Literatur darüber gefunden (wäre auch für einen Link
dankbar)
Gruß
Flo