Präprozess Makro >>> Fehler: undeclared

OP #4421024
Lesenswert?

Hallo.
Stehe gerade auf dem Schlauch;

Beim Kompilieren wird folgender Fehler angezeigt
'port' und 'mask' undeclared
in der Zeile
#define SET_BIT (port,mask) ((port) |= (1<<mask))

Daher habe ich verschiedene Präproz.-Aufrufe ausprobiert - ohne Erfolg.

Hatte schon ein paar mal den Präprozessor Makro genau so geschrieben - 
Funktionierte immer.
Angehängte Dateien:
Gast #4421106
Lesenswert?

A. K. schrieb:
> #define SET_BIT(port,mask) ((port) |= (1<<mask))

Hier ist ein Leerzeichen nach "SET_BIT" falsch, da es sich um ein Makro 
mit "port" und "mask" als Parameter handelt.

__Son´s B. schrieb:
> #define OBER_BEREICH (1023/15*11.5)

Hier muss ein Leerzeichen nach "OBER_BEREICH" eingefügt werden, da es 
sich nicht um ein Makro sondern um eine Wertdefinition handelt.
#4421137
Lesenswert?

Speckbert schrieb:
> __Son´s B. schrieb:
>> #define OBER_BEREICH (1023/15*11.5)
>
> Hier muss ein Leerzeichen nach "OBER_BEREICH" eingefügt werden, da es
> sich nicht um ein Makro sondern um eine Wertdefinition handelt.

Natürlich handelt es sich um ein Makro, allerdings um eines ohne 
Parameter.

__Son´s B. schrieb:
> ???
> Wie unterscheiden sich die Präproz.?
> Geht es darum, ob Werte zurück gegeben werden oder irgend etwas
> ausgelöst wird?

Nein, es geht darum, ob du an dein Makro Parameter übergeben willst. In 
dem Fall muss die Parameterliste mit ihren Klammern ohne Leerzeichen 
nach dem Namen stehen. Wenn dagegen die Klammer Teil des Inhalts des 
Makros ist, muss sie durch das Leerzeichen abgegrenzt werden. Irgendwie 
muss der Präprozessor das ja unterscheiden können.
Deshalb die Fehlermeldung bei:

__Son´s B. schrieb:
> #define OBER_BEREICH(1023/15*11.5)

Der Präprozessor erwartet in den Klammern eine Parameterliste und stellt 
dann fest, dass 1023 kein gültiger Parametername ist.
OP #4421143
Lesenswert?

OK!

Noch zwei Grundlagen, die ich nicht ganz zuordnen kann;
--1--
#define SET_BIT(port,mask) ((port) |= (1<<mask))
#define CLR_BIT(port,mask) ((port) &= ~(1<<mask))
#define LED_LOW(CLR_BIT(PORTB,PB0)) (CLR_BIT(PORTB,PB1)) 
(SET_BIT(PORTB,PB2))

Fehlermeldung für Zeile LED_LOW.
Darf ein Macro ein anderes Macro nicht direkt aufrufen?

--2--
In ADC_Init() warnt der Komp., dass "messwert" deklariert, aber nicht 
benutzt wird.
  uint16_t messwert;
Hier wird diese Var. in der letzten Zeile zugwiesen;
  messwert = ADCW;
Wie begründet sich die Warnmeldung?
#4421157
Lesenswert?

__Son´s B. schrieb:
> OK!
>
> Noch zwei Grundlagen, die ich nicht ganz zuordnen kann;
> --1--
> #define SET_BIT(port,mask) ((port) |= (1<<mask))
> #define CLR_BIT(port,mask) ((port) &= ~(1<<mask))
> #define LED_LOW(CLR_BIT(PORTB,PB0)) (CLR_BIT(PORTB,PB1))
> (SET_BIT(PORTB,PB2))
>
> Fehlermeldung für Zeile LED_LOW.

Gleicher Fehler wie vorher. Du gibst "CLR_BIT(PORTB,PB0)" als 
Parameterliste für dein Makro LED_LOW an. Das ergibt aber nicht viel 
Sinn.

> Darf ein Macro ein anderes Macro nicht direkt aufrufen?

Doch, darf es.

> --2--
> In ADC_Init() warnt der Komp., dass "messwert" deklariert, aber nicht
> benutzt wird.
>   uint16_t messwert;
> Hier wird diese Var. in der letzten Zeile zugwiesen;
>   messwert = ADCW;
> Wie begründet sich die Warnmeldung?

Wird der Inhalt denn irgendwann auch mal wieder gelesen? Eine Variable, 
in den ich einen Wert nur reinschreibe, ohne ihn nachher je wieder 
anzufassen, ist sinnlos.
OP #4421176
Lesenswert?

Kirsch schrieb:
> Einfach so:
> #define LED_LOW() (CLR_BIT(PORTB,PB1))
Funktioniert leider auch nicht!

A. K. schrieb:
> Was soll das darstellen?
Vereinfachung der Abfolge LED/high aus, LED/mid aus, LED/low ein

Alternative wäre aufwendiger;
main()...
SET_BIT(PORTB,PB0);
CLR_BIT(PORTB,PB1);
CLR_BIT(PORTB,PB2);
und das immer wieder, je nach Schaltungszustand.

Kirsch schrieb:
> zu 2
> nicht verwendet oder nicht gelesen?
In der Tat, ein Wert wird ausgelesen und in diese Var geschrieben, aber 
nicht weiter verwendet.
#4421189
Lesenswert?

__Son´s B. schrieb:
> #define LED_LOW(CLR_BIT(PORTB,PB0)) (CLR_BIT(PORTB,PB1))
> (SET_BIT(PORTB,PB2))
>
> Fehlermeldung für Zeile LED_LOW.

Das ist ja auch totaler Mist.

1.:
A. K. schrieb im Beitrag #4421150:
> Da fehlt mal wieder das Lerrzeichen.

2.:

Der Aufruf ist
1
LEDLOW;

Daraus wird:
1
PORTB &= ~(1 << PB0) PORTB &= ~(1 << PB1) PORTB |= (1 << PB2) ;

Fällt dir auf, was da fehlt?
Rictig! Hinter den ersten beiden Anweisungen fehlt das Semikolon.


1
#define SETLOW do{CLR_BIT(PORTB,PB0);\
2
          CLR_BIT(PORTB,PB1);\
3
          CLR_BIT(PORTB,PB0);}while(0)

So macht man das.
#4421196
Lesenswert?

Generell ist es sinnvoll, sich mal zu überlegen, was nach einer 
Makro-Ersetzung rauskommt und zu scahuen, ob das einen Sinn ergibt. 
Damit kommt man zumindest schneller zum Ziel als durch hin- und 
herschieben von Leerzeichen und mal probieren, ob's der Compiler 
schluckt.
OP #4421245
Lesenswert?

Mein grosses V. schrieb:
> Überleg dir mal, was passiert, wenn du schreibst:
while(1)
{
mit_wert = ADC_Read_Avg(3,64);
if (mit_wert > OBER_BEREICH) { LED_HIGH; }
if (mit_wert < UNTER_BEREICH) { LED_LOW; }
else { LED_MID; }
}

Nach meinm Verständnis, wird "mit_wert" in einer Dauerschleife 
ausgewertet und danach den 3 Bedingungen zu geordnet. Was soll daran 
"Mist" sein?
#4421263
Lesenswert?

__Son´s B. schrieb:
> if (mit_wert > OBER_BEREICH) { LED_HIGH; }

Das habe ich auch nicht geschrieben, sondern das:
1
if(blabla) LEDHIGH;

Und daraus wird:
1
if(blabla) Anweisung1;
2
Anweisung2;
3
Anweisung3;

D.h., daß Anweisung1 in Abhängigkeit von blabla ausgeführt wird, 
Anweisung2 und 3 dagegen immer. Das ist aber nicht Sinn der Sache.

Du zwingst dich damit, immer hinter der if-Abfrage Klammern zu setzen. 
Das ist bei nur einer folgenden Anweisung aber gar nicht notwendig. Das 
funktioniert jetzt, da du es weisst. Damit schiesst du dir aber 
langfristig ins Knie.
Mach es vernünftig!
#4421266
Lesenswert?

__Son´s B. schrieb:
> Was soll daran "Mist" sein?

Die Erklärung von "Mein grosses Vorbild" hat da noch etwas 
Optimierungspotenzial.

Es ging ihm darum, dass du das Makro nicht genau wie eine Funktion 
behandeln kannst, da es mehrere statements beinhaltet. Dadurch können 
unerwartete Effekte auftreten wie z.B. in:
1
#define X() a(); b()
2

3
if (z == 3) X();

Man erwartet, dass a() und b() nur aufgerufen werden, wenn z den Wert 3 
hat. Tatsächlich wird b() aber immer aufgerufen. Denn durch die 
Makro-Ersetzung entsteht:
1
if (z == 3) a(); b();
oder etwas klarer eingerückt:
1
if (z == 3)
2
    a();
3
b();

Aus dem Grund wird in Makros, die mehrere statements zusammenfassen, 
gerne ein do {} while(0) darum herum geschrieben. Das tut letztendlich 
nichts anderes, als den Code zwischen den Klammern genau einmal 
auszuführen, aber es ist insgesamt wieder ein einzelnes Statement. Damit 
funktioniert die obige Abfrage auch wie erwartet:
1
#define X() do  { a(); b(); } while (0)
2

3
if (z == 3) X();
wird ersetzt durch:
1
if (z == 3)
2
    do
3
    {
4
        a();
5
        b();
6
    } while(0);
Durch den Trick mit dem do/while wird b genau wie a in der Bedingung 
ausgeführt.
#4421306
Lesenswert?

__Son´s B. schrieb:
> ahhh! Es ging also nur um meinen Minimal-Auszug;

Nein. Es geht darum, dir zu zeigen, wie man vernünftige Makros mit 
mehreren enthaltenen Anweisungen schreibt.

__Son´s B. schrieb:
> Klar kann das in c nicht einfach nur "dumm" rum stehen...

Natürlich kann man das. Aber willst du dir jeden Spezialfall deiner 
Makros merken?

Sinn der Übung ist, daß du gar nicht unbedingt wissen musst, daß das ein 
Makro ist, sondern du dieses genauso wie eine Funktion benutzen kannst 
und benutzen musst. Mit allen Spezialitäten bei der Abfrage von 
Bedingungen oder der Benutzung in Schleifen.

Konsequenterweise kann man das auch so schreiben:
1
#define Makro() do{...}while(0)
2

3
Makro();
4

5
while(1)Makro();
6

7
while(1)
8
{
9
  Makro();
10
}
11

12
if(Bla) Makro(); else {...}
13

14
if(Bla) 
15
{
16
 Makro();
17
} else {...}

Kriegst du die Aufrufe mit deiner Version auch hin? Nein. Bei zwei 
Aufrufen fliegst du auf die Schnauze. Und vor allen Dingen: Weißt du das 
in einem Jahr noch?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren