Forum: Mikrocontroller und Digitale Elektronik Mehrzeiliges Makro funktioniert nicht


von Flo (Gast)


Lesenswert?

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ß

von Bernhard M. (boregard)


Lesenswert?

zu viele Leerzeichen, bei den Parametern dürfen keine sein...
1
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE)         \
2
(                                                       \
3
    ((BYTE)_DESTBYTE_) |=  0x0F                        ;\
4
    ((BYTE)_DESTBYTE_) ^= ~0x0F                        ;\
5
    ((BYTE)_DESTBYTE_) |= (SOURCEBYTE & 0x0F)         \
6
)

von Flo (Gast)


Lesenswert?

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 );

von Bernhard M. (boregard)


Lesenswert?

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:
1
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE)         \
2
(                                                       \
3
    ((BYTE)(DESTBYTE)) |=  0x0F                        ;\
4
    ((BYTE)(DESTBYTE)) ^= ~0x0F                        ;\
5
    ((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F)        ;\
6
)

von Bernhard M. (boregard)


Lesenswert?

Noch was:
was soll das Makro denn tun? Momentan sieht es teilweise sinnfrei aus..

von Flo (Gast)


Lesenswert?

#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

von Flo (Gast)


Lesenswert?

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)

von Bernhard M. (boregard)


Lesenswert?

warum nicht:
1
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE)         \
2
(                                                       \
3
    ((BYTE)(DESTBYTE)) &=  0xF0                        ;\
4
    ((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F)        ;\
5
)

von Bernhard M. (boregard)


Lesenswert?

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...

von Flo (Gast)


Lesenswert?

Da man damit da HighNibble auf F setzen würde ich möchte aber das 
High-Nibble unberührt lassen.

von Bernhard M. (boregard)


Lesenswert?

Nein, das High Nibble bleibt unberührt, weil es eine UND Verknüpfung 
ist...

von Flo (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Flo (Gast)


Lesenswert?

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

von Bernhard M. (boregard)


Lesenswert?

Mach mal:
1
#define NIBL2NIBL(SOURCEBYTE,DESTBYTE)         \
2
    ((BYTE)(DESTBYTE)) &=  0xF0                        ;\
3
    ((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F)

von Flo (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Bernhard M. wrote:
> Mach mal:
>
1
> #define NIBL2NIBL(SOURCEBYTE,DESTBYTE)         \
2
>     ((BYTE)(DESTBYTE)) &=  0xF0                        ;\
3
>     ((BYTE)(DESTBYTE)) |= ((SOURCEBYTE) & 0x0F)
4
>


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.

von Flo (Gast)


Lesenswert?

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

von Bernhard M. (boregard)


Lesenswert?

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 ;-)

von Flo (Gast)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.)

von Bernhard M. (boregard)


Lesenswert?

Dann lass den Cast auf BYTE weg, der ist eh nicht richtig sinnvoll...

von Bernhard M. (boregard)


Lesenswert?

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...

von Flo (Gast)


Lesenswert?

OK damit ist jetzt alles klar...
also nachmals vielen lieben dank für die superschnelle Problemlösung...

Gruß

Flo

von Michael König (Gast)


Lesenswert?

> 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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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...

von Bernhard M. (boregard)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Flo (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Seite 68 (mit der Seitennummer 56).

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
Noch kein Account? Hier anmelden.