mikrocontroller.net

Forum: Compiler & IDEs Preprozessor Problem


Autor: Andy (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

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

Autor: OldBug (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 */
[..]

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@OldBug,

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


Peter

Autor: OldBug (Gast)
Datum:

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

Autor: Michael (ein anderer) (Gast)
Datum:

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

Autor: OldBug (Gast)
Datum:

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

Autor: Rufus T. Firefly (Gast)
Datum:

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

Autor: Michael (ein anderer) (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Rufus T. Firefly (Gast)
Datum:

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

Autor: Zotteljedi (Gast)
Datum:

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

Autor: Zotteljedi (Gast)
Datum:

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

Autor: Rufus T. Firefly (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein heutiger Dank geht an den Zotteljedi.

Dir sei ein virtuelles Bier ausgegeben.

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.