www.mikrocontroller.net

Forum: Compiler & IDEs sauberes #define


Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forenuser.
ich habe mir aus den Codebeispielen diese schönen Zeilen zum setzen und
löschen von Bits kopiert
  #define setbit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
Nun möchte ich aber dieses weitertreiben, so dass ich Proceduren auch
auf anderen Ports oder anderen Prozessoren benutzen kann.
also z.B. einen gepulsten Port für IR-Kommunikation.
Wenn ich das in dieser Form mache
 #define ir_transmit PORTA,PA6
gibts einen Fehler bei
setbit(ir_transmit);
mit der Begründung
macro "setbit" requires 2 arguments, but only 1 given
Die Fehlermeldung ist klar.
Versteht der Compiler nicht, dass es sich bei ir_transmit um 2
Argumente handelt?
Wie macht man es richtig?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Versteht der Compiler nicht, dass es sich bei ir_transmit um 2
> Argumente handelt?

Für den Präprozessor ist es nur 1 Argument.

> Wie macht man es richtig?
#define s(a,b) do { (a) |= 1 << (b); } while (0)
#define setbit(x) s(x)
#define x PORTD,2

setbit(x)

Schräg, ja, ich weiß. :-)

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das SETBIT ist selbst schon ein Makro. Der Präprozessor merkt sich eine
Liste von allen Defines zum späteren ersetzen. Wenn im Sourcecode die
vorgesehene Ersetzung von SETBIT vor der Ersetzung von IR_TRANSMIT
abgearbeitet wird, kommt die Fehlermeldung. Du müsstest zusehen, dass
das define von IR_TRANSMIT dem Präprozessor zuerst bekannt wird.

Tipp: Wenn man Makros grundsätzlich nur in Grossbuchstaben schreibt,
sieht man eher was im Sourcecode los ist.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Schräg, ja, ich weiß. :-)"


Wow !

Die Typüberprüfung erfolgt also nur bei der ersten Macroexpansion und
läßt sich durch 3-fach Macros überlisten.

Ist das nun ein Bug oder ein Feature des AVR-GCC ?

Ist das auch bei anderen Compilern so ?


Peter



P.S.:
Muß ich gleich mal ausprobieren.

Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich schließe mich dem wow an.
Wäre Stefans lösung auch ok? Dann bliebe nämlich die Funktion von
SETBIT für einzeln zu setzende Bits erhalten oder führt das ggf zu
anderen Problemen?

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ist das nun ein Bug oder ein Feature des AVR-GCC ?

Kein Bug! Schau mal da:

http://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments....

Wichtig ist folgender Abschnitt:

All arguments to a macro are completely macro-expanded before they are
substituted into the macro body. After substitution, the complete text
is scanned again for macros to expand, including the arguments. This
rule may seem strange, but it is carefully designed so you need not
worry about whether any function call is actually a macro invocation.
You can run into trouble if you try to be too clever, though. See
Argument Prescan, for detailed discussion.

> Ist das auch bei anderen Compilern so ?

Das ist das im ISO-Standard so vorgesehen. Allerdings gab es in der
Vergangenheit etliche Compiler bzw. Präprozessoren (einschließlich
derjenigen von Microsoft), die diese Regel falsch umsetzten, so dass
das entweder beim Konstrukt von flyingwolf fälschlicherweise kein
Fehler oder bei dem von Jörg fälschlicherweise ein Fehler ausgegeben
wurde.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ flyingwolf

Kann ich selbst beantworten: Vergiss es wieder. Klappt nicht! Habe es
gerade ausprobiert. Sorry!

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Variante von Jörg funktioniert auch bei Digital Mars, nicht jedoch
bei Microsoft (warning C4003: Nicht genügend übergebene Parameter für
das Makro 'setbit2').

Eine Variante, die aber bei allen korrekten Präprozessoren
funktionieren sollte, und die sich elegant auf Funktionen auf die
PINA/DDRA Register erweitert:
#define ir_transmit_PORT  A
#define ir_transmit_PIN   6

#define p_port(x)  x##_PORT
#define p_pin(x)  x##_PIN
#define p_in(x)  PIN##x
#define p_out(x)  PORT##x
#define p_dir(x)  DDR##x
#define pp_in(x)  p_in(x)
#define pp_out(x)  p_out(x)
#define pp_dir(x)  p_dir(x)

#define testbit(x) (pp_in(p_port(x)) & 1<<p_pin(x))
#define setbit(x)   (pp_out(p_port(x)) |= 1<<p_pin(x))
#define clrbit(x)   (pp_out(p_port(x)) &= ~(1<<p_pin(x)))
#define setout(x)   (pp_dir(p_port(x)) |= 1<<p_pin(x))
#define setinp(x)   (pp_dir(p_port(x)) &= ~(1<<p_pin(x)))

void
f(void)
{
    if (testbit(ir_transmit)) {
  do_something();
    }
    setout(ir_transmit);
    setbit(ir_transmit);
}

Resultat ist:
void
f(void)
{
    if ((PINA & 1<<6)) {
        do_something();
    }
    (DDRA |= 1<<6);
    (PORTA |= 1<<6);
}

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Variante von Volker ist aber auch nicht schlecht:

http://www.mikrocontroller.net/forum/read-1-324854.html#new


Da hat man sogar wieder die vom 8051 gewohnten Bitvariablen.

Also ideal, um C51 Programme zu portieren.


Peter

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitfelder werden vom Compiler leider meist ausgesprochen ineffizient
implementiert.

Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitfelder = struct?
Da habe ich letztens was interessantes gesehen. Alle Variablen waren in
einer Struktur definiert auch die 1-Bit-Vars und dann wurde die ganze
Structur ins EEProm geschrieben.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Bitfelder = struct?"

Ja. wenn sowas wie
    unsigned b1 : 1;
drin ist.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich hab das mit den Bitfeldern ausprobiert.

Zumindest der AVR-GCC macht dann die SBI- und CBI-Befehle draus, ganz
so wie es sein soll.


Peter

Autor: Dirk Bxxxxx (dirk-)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

>Also ich hab das mit den Bitfeldern ausprobiert.

>Zumindest der AVR-GCC macht dann die SBI- und CBI-Befehle draus, ganz
>so wie es sein soll.

@Peter

Weisst du wie es bei Keil und 8051er aussieht?

Gruß,

Dirk

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Solange es um einzelne Bits geht, kann der Compiler was draus machen -
wenngleich ich auch schon abschreckende Beispiele gesehen habe (weiss
bloss nicht mehr wo).

Der Haken bei Bitfeldern liegt aber wesentlich auch darin, dass man
keine Chancen hat, es besser zu machen. Jedenfalls nicht solange man
bei den Bitfeldern bleibt und nicht nebenbei noch die klassischen
Register und Bits pflegt. Sowas wie
   ControlRegister |= 1<<Enable | 1<<CrashAndBurn;
ist bei Bitfeldern nicht drin, und
   ControlRegister.Enable = 1;
   ControlRegister.CrashAndBurn = 1;
darf bei dem natürlich als "volatile" deklarierten ControlRegister
kein Compiler legal zusammenfassen (wenngleich SDCC sowas ähnliches
fertigbringt). Mit CBI/SBI ist das ok, u.U. sogar besser, bei nicht
bitweise adressierbaren Adressen zieht sich das jedoch arg in die
Länge.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Weisst du wie es bei Keil und 8051er aussieht?"


Beim Keil kann man mit "sbit" einzelne Bits einer bitadressierbaren
Variable definieren. Näheres im Keil Handbuch oder auf deren Webseite
(Knowledegbase).


Peter

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.