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 ?
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
Was hälst Du denn davon: #define P0_N_RESET (1 << 7) [..] PORTB |= P0_N_RESET; /* set bit */ [..] PORTB &= ~P0_N_RESET; /* clear bit */ [..]
@OldBug, na dann fröhliches Editieren des gesamten Quelltextes, wenn mal ein Pin den Port wechselt. Peter
Stimmt auch wieder... Naja, sbi ist jedenfalls deprecated und jede andere Lösung ist besser ggg
#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)
Was soll eigentlich dieses do...while(0) bewirken? Da war irgendwas mit "if"s, aber kapiert hab ich das noch nicht...
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.
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.
@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
@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
"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.
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.
> 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.