Forum: Compiler & IDEs Preprozessor Problem


von Andy (Gast)


Lesenswert?

Hi,

ich habe ein Preprozessor Problem mit dem Makro sbi.

Folgendes habe ich zusammengebaut:

#define P0_N_RESET     PORTB,7
...
void init(void)
  {
  sbi(P0_N_RESET);
      }
...

Der GCC bringt nun folgende Fehlermeldung:
my_p0.h:20:20: macro "sbi" requires 2 arguments, but only 1 given

Mir ist klar, dass er es nicht check, dass er erst P0_N_RESET ersetzen
muss. Aber was kann ich tun ?

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Gute Frage, nächste Frage.

Aber es gibt eine Lösung, wenn auch keine so einfache.
Im Anhang ist ein Beispiel dazu.

Ich finde es auch schöner, wenn man Bits mit einem Namen definieren
kann.


Peter

von OldBug (Gast)


Lesenswert?

Was hälst Du denn davon:

#define P0_N_RESET    (1 << 7)

[..]
    PORTB |= P0_N_RESET;     /* set bit   */
[..]
    PORTB &= ~P0_N_RESET;    /* clear bit */
[..]

von Peter D. (peda)


Lesenswert?

@OldBug,

na dann fröhliches Editieren des gesamten Quelltextes, wenn mal ein Pin
den Port wechselt.


Peter

von OldBug (Gast)


Lesenswert?

Stimmt auch wieder... Naja, sbi ist jedenfalls deprecated und jede
andere Lösung ist besser ggg

von Michael (ein anderer) (Gast)


Lesenswert?

#define    SBI(p, b)   do { (p) |= 1<<(b) } while(0)
#define    CBI(p, b)   do { (p) &= ~(1<<(b)) } while(0)

#define    LED_PORT    PORTx
#define    LED_BIT     3

#define    LED_ON()    SBI(LED_PORT, LED_BIT)
#define    LED_OFF()   CBI(LED_PORT, LED_BIT)

von OldBug (Gast)


Lesenswert?

Was soll eigentlich dieses do...while(0) bewirken?
Da war irgendwas mit "if"s, aber kapiert hab ich das noch nicht...

von Rufus T. Firefly (Gast)


Lesenswert?

Das ist mir allerdings auch unklar.

#define    SBI(p, b)   do { (p) |= 1<<(b) } while(0)

hätte ich so geschrieben

#define    SBI(p, b)   ((p) |= 1<<(b))

Man muss allenfalls den Compiler anweisen, daß p volatile ist, aber das
sollte in den entsprechenden Headerdateien ja eh' so definiert sein.

von Michael (ein anderer) (Gast)


Lesenswert?

Das "do { ...} while(0)" wird benötigt, um zu erreichen dass das Makro
sich exakt gleich verhält wie ein normaler Funktionsaufruf, d.h. das
Makro stellt ein Statement da.

Übrigens habe ich einen kleinen Fehler gemacht, ich habe die
Strichpunkte vergessen (schäm).

Hier ein kleines Beispiel:


#define     BAD(a)   (bla = (a))
#define     GOOD(a)   do { bla = (a); } while(0)

int bla;

int main()
{
  BAD(123), "abc";   /* Hier meckert der Compiler nicht!!! */

  GOOD(123), "abc";  /* Hier bricht der Compiler mit einem Fehler ab
*/

  return 0;
}


Das Makro BAD ist ein Assignment, also eine Expression. Das Makro GOOD
ist ein Statement.

von Peter D. (peda)


Lesenswert?

@Michael (ein anderer)

"Das "do { ...} while(0)" wird benötigt, um zu erreichen dass das
Makro
sich exakt gleich verhält wie ein normaler Funktionsaufruf, d.h. das
Makro stellt ein Statement da."


Ich verstehe nur Bahnhof.
Wozu braucht man denn sowas ?
Ein Statement ist alles, was ein ; hat oder in {} eingeschlossen ist.


Statt do{...}while(0) nehme ich lieber for(;;){...break;}, ist halt
Geschmackssache.
Als einzige Anwendung für sowas kenne ich bisher nur, daß man mehrere
Abbruchbedingungen testen will, also mit if(...)break; abbricht.



@Alle

Ich habe das original Posting so verstanden, daß er den Pin nur mit
einem einzigen Namen versehen will, d.h. daß der Name die Byte- und die
Bitadresse enthält.

Und das macht nur meine Lösung.


Peter

von Peter D. (peda)


Lesenswert?

@Michael (ein anderer)

Ich hab das mal ausprobiert:


char i;

char bla( void )
{
  return 7;
}


void test( void )
{
  i = bla(), "abc";

  "abc";

  i = 5, "abc";

  do{ i = 6; }while(0), "abc";
}

Nur die letzte Zuweisung ergibt eine Fehlermeldung, d.h. sie verhält
sich nicht wie ein Funktionsaufruf !!!

Funktionsaufrufe könne durchaus sinnvoll durch Komma getrennt werden.

In allen anderen Zeilen wird "abc" vom Compiler als Nonsens
betrachtet und einfach ignoriert.
Man muß halt wissen, was man hinschreibt und ich wüßte jetzt absolut
nicht, warum jemand sowas hinschreiben sollte.


Peter

von Rufus T. Firefly (Gast)


Lesenswert?

"Das "do { ...} while(0)" wird benötigt, um zu erreichen dass
   das Makro sich exakt gleich verhält wie ein normaler
   Funktionsaufruf, d.h. das Makro stellt ein Statement da."

Das scheint nur für Leute von Bedeutung zu sein, die mehrere durch
Semikola getrennte Dinge in eine Zeile schreiben und sich vom Compiler
auf die Finger klopfen lassen wollen, wenn sie Komma und Semikolon
verwechseln.

Es gibt Probleme, von denen man gar nicht wusste, daß Leute sie haben
können.

von Zotteljedi (Gast)


Lesenswert?

Der Kommaoperator wird übrigens in § 6.5.17 vom Standard beschrieben,
und ist ein Sequence-Point.

Man kann mehrere Funktionen etc. damit trennen, sollte aber immer daran
denken, daß der rechte Operand den Gesamtausdruck bestimmt, da kann man
böse auf die Fresse fallen.

Man kann sich auch darauf verlassen, daß der Kommaoperator geringere
Bindung als die Zuweisung (=) hat, aber Ausdrücke wie

p = i = 5, "abc";

sind dadurch schwerer lesbar, man muß also wissen, daß sie als

(p = i = 5), "abc";

und nicht als

p = (i = 5, "abc");

ausgewertert werden. Im ersten Fall steht in p (das z.B. char* sein
könnte) eine 5, im letzten Fall die Adresse von "abc", und das könnte
für den Rest des Programms von entscheidender Wichtigkeit sein ;-)

Spaß mit Auswertung und Sequence-Points kann man vor allem mit && und
|| haben, wenn man ifs sparen und den Code verkomplizieren will.

a || (b = 5);

als Abkürzung für

if (!a)
  b = 5;

und Faxen dieser Art. Nicht genutzte aber bewertete Statements wie
obiges "abc"; sind eigentlich nur lustig, um Anfänger in den Wahnsinn
zu treiben, wenn man z.B. mal ein

42;

in den Code einstreut. Alle Leute mit -Werror werden sich bedanken.

von Zotteljedi (Gast)


Lesenswert?

> Es gibt Probleme, von denen man gar nicht wusste, daß Leute sie
> haben können.

Jupp, siehe auch

if (i == 42)

vs.

if (42 == i)

Ich empfinde die erste Variante beim Lesen als "logischer", viele
bevorzugen die letzte, weil sie gegen Vertipper schützt. Naja,
Geschmackssache eben.

von Rufus T. Firefly (Gast)


Lesenswert?

Mein heutiger Dank geht an den Zotteljedi.

Dir sei ein virtuelles Bier ausgegeben.

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.