Forum: Mikrocontroller und Digitale Elektronik Wie schreibe ich ein einfaches Makro in C?


von Kevin J. (noway)


Lesenswert?

Hallo zusammen.

Von Assembler nach C umgestiegen, frage ich mich nun, wie man in C ein 
Makro schreibt. So schwer kann das eigentlich nicht sein, aber 
offensichtlich habe ich im Moment ein Brett vorm Kopf >_<

In Assembler würde man ja schreiben:

Name_des_Makros MAKRO

befehle
befehle

#endm

Wie würde man denn jetzt so etwas simples in C bewerkstelligen?

von Johannes M. (johnny-m)


Lesenswert?

1
 #define MAKRONAME DEFINITION
C-Buch lesen...

von Martin (Gast)


Lesenswert?

z.B. so

#define warte  \
{              \
 while(i++);   \
}

von Karl H. (kbuchegg)


Lesenswert?

Wobei Assembler Makros in C oft besser durch eine Funktion realisiert 
werden.

von ... (Gast)


Lesenswert?

> Kevin J. (Firma: FZ-Juelich) (noway)
Schwer zu glauben, dass es im FZ-Juelich kein C-Buch gibt...

von Kevin J. (noway)


Lesenswert?

Ah natürlich ja...Bücher vorn Kopf klatsch
Hätte ich eines hier hätte ich auch nachgeschlagen -.- Solche Kommentare 
kann man sich doch schenken. Aber das hat ja auch was, indem man 
"Neulingen" einfach direkt einen vor den Bug ballert und ihnen die 
Motivation mit solch schlauen Sprüchen raubt...

Zum Thema:

Die Idee von Martin werde ich ausprobieren. Danke dafür.

von Sven W. (woehlb)


Lesenswert?

Martins Lösung ist meiner Meinung nach nicht ganz vollständig (siehe 
Parameterliste des Makros). ;-)

Definition des Makros:

#define warte(i)\
{               \
 while(i++);    \
}

Anwendung des Makros:

warte(1000);


Tschau Sven!

von Johannes M. (johnny-m)


Lesenswert?

...und es ist meist sinnvoll, Makronamen in GROSSBUCHSTABEN zu 
schreiben, um sie von Funktionen/Variablen unterscheiden zu können.

von Dieter E. (netdieter) Benutzerseite


Lesenswert?

> Die Idee von Martin werde ich ausprobieren. Danke dafür.

Es macht mehr Sinn sich an den Vorschlag von Karl heinz Buchegger zu 
halten.

Sinn und Zweck eines Makros ist es doch, das der gleiche Code an 
verschiedenen Stellen ausgeführt wird. Das erreichst Du am elegantesten, 
durch eine Funktion.

Also z.B.
1
void warte(){
2
  while(i < j){
3
      ......
4
  }
5
}

DEFINES werden eher dafür benutzt um Compilerabhängige Codeanpassungen 
vorzunehmen.

Such einfach mal nach C Tutorial und lies doch ein paar Seiten.

von Johannes M. (johnny-m)


Lesenswert?

Dieter Engelhardt wrote:
> Sinn und Zweck eines Makros ist es doch, das der gleiche Code an
> verschiedenen Stellen ausgeführt wird. Das erreichst Du am elegantesten,
> durch eine Funktion.
Die hat aber, im Gegensatz zu einem "echten" Makro (das nur eine 
Textersetzung vornimmt) einen oft nicht erwünschten Overhead. In dem 
Fall sollte man die fragliche Funktion eventuell inline deklarieren...

von Sven P. (Gast)


Lesenswert?

Johannes M. wrote:
> Fall sollte man die fragliche Funktion eventuell inline deklarieren...

Und nen aktuellen GCC dazu benutzen...

von Johannes M. (johnny-m)


Lesenswert?

Sven P. wrote:
> Und nen aktuellen GCC dazu benutzen...
Na, das doch sowieso...

von Sven W. (woehlb)


Lesenswert?

@ Dieter Engelhardt:

Hallo Dieter!

Es tut mir leid, aber da kann ich Dir so nicht zustimmen.

1) Mit Funktionen erreichst Du, daß ein und der selbe Code von 
unterschiedlichen Stellen des Programms aus zur Laufzeit angesprungen 
und ausgeführt werden kann.

2) Definierst Du ein Makro und benutzt es an mehren Stellen, wird immer 
wieder der selbe Code beim Übersetzen des Quellcodes in das Programm 
eingefügt (an jeder Stelle, an der das Makro benutzt wurde). Aus diesem 
Grund sollte man auch mit Makros vorsichtig sein, um das Programm nicht 
aufzublähen. Aufgrund der fehlenden Sprünge läuft es aber schneller. Die 
Verwendung von Makros lohnt sich bei kurzen Befehlssequenzen.

@Karl heinz Buchegger:

>Wobei Assembler Makros in C oft besser durch eine Funktion realisiert
>werden.

Was meinst Du damit genau? In Martins Beispiel handelt es sich doch um 
ein C-Makro.

Tschau Sven!

von Sven W. (woehlb)


Lesenswert?

@Johannes M.

Mit inline definierte Funktionen als Alternative hast du natürlich 
recht.

Gibt es zwischen inline definierten Funktionen und Makros irgendwelche 
wichtigen Unterschiede bei der Abarbeitung?

von !Klaus (Gast)


Lesenswert?

Ihr habt alle die Frage nicht verstanden.

So und NUR so schreibt man ein einfaches Makro in C:

printf("ein einfaches Makro in C:");

von Chris (Gast)


Lesenswert?

makros mit #define wait(i) {while(...);} funktionieren bei
if (test(foo)) wait(i); else bar();

Da merkst du selbst, daß das nicht funktioniert.
Deshalb verwendet man

#define wait(i) do {...} while(0)
weil da das Semikolon obligatorisch ist, und es dann kein null-statement
ist, was dir jede if/while/... Abfrage verhunzt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sven Woehlbier wrote:
> #define warte(i)\
> {               \
>  while(i++);    \
> }
>
> Anwendung des Makros:
> warte(1000);
Tolles Makro  :-o
Frage: Wie lange zählt das denn hoch?
Antwort: bis zum Überlauf der übergebenen Zahl.

Überhaupt bin ich mir nicht ganz sicher, dass genau dieser Aufruf 
funktionieren wird. Denn was macht der Preprozessor daraus?
>  { while(1000++); }
Macht das Sinn?

von Karl H. (kbuchegg)


Lesenswert?

Sven Woehlbier wrote:

>>Wobei Assembler Makros in C oft besser durch eine Funktion realisiert
>>werden.
>
> Was meinst Du damit genau? In Martins Beispiel handelt es sich doch um
> ein C-Makro.

Es gibt genügend Fallstricke bei C-Makros.
Legionen von Programmieren sind darauf hereingefallen und werden es auch 
weiter tun.
Solange man weiß was man tut, können Makros nützlich sein. Hab selbst 
schon jede Menge Unfug mit Makros angestellt.
Aber irgendwann kommt man zur Erkenntnis, das man abwägen soll und muss, 
ob man eine bestimmte Funktionalität mit Makros oder mit einer Funktion 
realsiert. Makros als Funktionsersatz für generische Funktionen sollte 
gesetzlich verboten werden.

1
#define max(a,b)  ( (a) > (b) ? (a) : (b) )

und dann viel Spass beim Suchen warum zwar
1
     i = max( a, b );
funktioniert, sich aber
1
     j = max( i++, b );
"seltsam" verhält (nur um mal eines der prominentesten Beispiele zu 
benutzen. Die Liste ist beliebig verlängerbar).
Oder warum in
1
     k = max( NrOfEntries(), 100 );
die Funktion NrOfEntries manchmal, aber nicht immer, 2 mal aufgerufen 
wird. Wobei das bei einer Abzählfunktion ja noch relativ glimpflich ist, 
wenn aber von einem Konto ein bestimmter Betrag manchmal 2 mal abgebucht 
wird, dann erklär das mal deinem Kunden. Und vor allen Dingen find 
diesen Bug mal in einem Programm. Die Fehlermeldung deines Kunden 
lautet: Manchmal wird eine Abbuchung doppelt gemacht. Und dann stell da 
mal die Beziehung dazu her, dass du den Abbuchbetrag gegen einen 
Maximalbetrag getestet hast und das das die Ursache für die 2-te 
Abbuchung war.

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller wrote:

> Überhaupt bin ich mir nicht ganz sicher, dass genau dieser Aufruf
> funktionieren wird. Denn was macht der Preprozessor daraus?
>>  { while(1000++); }
> Macht das Sinn?

Ich bin auch neugierig welche und wie verständlich die Fehlermeldungen 
des Compilers sind, sollte jemand mal auf die Idee kommen
1
  warte( GetWaitingTime() );

zu schreiben :-)

von ... (Gast)


Lesenswert?

> Hätte ich eines hier hätte ich auch nachgeschlagen -.-
Alternative -> Internet-Tutorials! Du lernst heute soviel Neues... ;-)
> Solche Kommentare kann man sich doch schenken. Aber das hat ja auch
> was, indem man "Neulingen" einfach direkt einen vor den Bug ballert und
> ihnen die Motivation mit solch schlauen Sprüchen raubt...
Was glaubst du eigentlich wie demotivierend Fragen wie die deine oben
sind? Irgendwann hat gar keiner mehr Lust zu antworten...

von Karl H. (kbuchegg)


Lesenswert?

Kevin J. wrote:
> Ah natürlich ja...Bücher *vorn Kopf klatsch*
> Hätte ich eines hier hätte ich auch nachgeschlagen -.- Solche Kommentare
> kann man sich doch schenken. Aber das hat ja auch was, indem man
> "Neulingen" einfach direkt einen vor den Bug ballert und ihnen die
> Motivation mit solch schlauen Sprüchen raubt...

Wenn ich dir so zuhöre wundert es mich direkt wie Millionen von 
Programmierern vor der "Erfindung" des Internet überhaupt Programmieren 
erlernen konnten. Man war das damals demotivierend die IBM JCL Manuals 
tage-, ja wochenlang zu studieren.

von Sven W. (woehlb)


Lesenswert?

@ Lothar Miller:

Kritik angekommen! Habe leider das Beispiel von Martin zu kritiklos 
übernommen. Hier jetzt aber ein lauffähiges Makro.


#define DELAY(pause){\
  clock_t start = clock();\
  while( (((clock()-start)*1000)/CLK_TCK) < pause );\
}

von Karl H. (kbuchegg)


Lesenswert?

Sven Woehlbier wrote:
> @ Lothar Miller:
>
> Kritik angekommen! Habe leider das Beispiel von Martin zu kritiklos
> übernommen. Hier jetzt aber ein lauffähiges Makro.
>
>
> #define DELAY(pause){\
>   clock_t start = clock();\
>   while( (((clock()-start)*1000)/CLK_TCK) < pause );\
> }


Das kann (muss nicht) wiederrum für denjenigen, der dieses Makro 
benutzt zu seltsamen Effekten führen. Überleg dir einfach bei jedem(!) 
Makro das du schreibst, was wohl passieren wird, wenn du als Argument 
eine Variable++ einsetzt bzw. das Ergebnis eines Funktionsaufrufs 
benutzt.
1
  int Wartezeit = 0;
2
3
  while( Wartezeit < 100 ) {
4
    ToggleLed();
5
    DELAY( Wartezeit++ );
6
  }

verhält sich völlig anders, als man intuitiv beim Studim dieser 
Codezeilen erwarten würde. Um Ordnung in dieses Chaos zu bekommen, muss 
man die Internals von DELAY kennen, etwas was ich bei einer 
gleichnamigen Funktion delay() nicht muss. Immerhin warst du freundlich 
genug und hast den Makro Namen gross geschrieben, so dass jemand, der 
dieses Makro verwendet gewarnt ist und das Makro studiert ehe er es 
benutzt. Aber Hand aufs Herz: Willst du jedesmal, wenn du vorgefertigte 
Funktionalität benutzt erst überlegen müssen, wie das Makro wohl 
expandiert und ob es da mglw. zu Semantischen Fehlern kommen kann?

von Chris (Gast)


Lesenswert?

#define DELAY(pause){\
  clock_t start = clock();\
  while( (((clock()-start)*1000)/CLK_TCK) < pause );\
}

das schreibt man so

#define DELAY(pause)do {\
  clock_t start = clock();\
  while( (((clock()-start)*1000)/CLK_TCK) < pause );\
} while(0)

oder für GCC auch so,
#define DELAY(pause)({\
  clock_t start = clock();\
  while( (((clock()-start)*1000)/CLK_TCK) < pause ); 1; \
})

da kann man es nähmlich auch als Expression nutzen, wie wenn es eine
Funktion wäre, z.B.  foo?DELAY(100):bar oder auch anders, ist für
Delay vielleicht nicht so angebracht.

von Chris (Gast)


Lesenswert?

#define DELAY(pause)do {\
  clock_t start = clock();\
  while( (((clock()-start)*1000)/CLK_TCK) < pause );\
} while(0)

Sollte so sein, habe mir den Code zu wenig angesehen.

#define DELAY(pause)do {\
  clock_t end = clock() + ((pause)*1000/CLK_TCK);\
  while( (((clock()) < end );\
} while(0)

von Sven W. (woehlb)


Lesenswert?

@Karl heinz Buchegger

Hallo Karl-Heinz!

Vielen Dank, für Deine Hinweise! Ich mußte erst auf Lothar reagieren, 
und wenigstens ein korrektes Makro präsentieren.

Auf die Idee das Makro mit Funktionsaufrufen und Variablen 
auszuprobieren, bin ich ehrlich gesagt noch nicht gekommen. Ich habe es 
ausschließlich mit einer Konstanten im Aufruf benutzt.

z.B. DELAY(1000);

Hintergrund bei der Sache ist, der Borland-Compiler, den ich hier 
benutze, unterstützt das alte delay() nicht mehr. Manchmal ist man eben 
nicht ganz frei in der Auswahl der Werkzeuge. Insgesamt hast Du aber 
recht, für einen anderen Programmierer könnte die Verwendung des Makros 
problematisch sein.

Ich glaube, wenn es dann etwas makro-ähnliches sein muß, sind mir die 
Inline Funktionen dann doch lieber.

Vielen Dank!
Tschau Sven!

von Karl H. (kbuchegg)


Lesenswert?

Sven Woehlbier wrote:

> Ich glaube, wenn es dann etwas makro-ähnliches sein muß, sind mir die
> Inline Funktionen dann doch lieber.

Du bist am richtigen Weg!

genauso effizient wie Makros, nur dass sich der Compiler um diese ganzen 
kleinen Fallen kümmert :-)

von Buch C (Gast)


Lesenswert?

@... (Gast)
>> Schwer zu glauben, dass es im FZ-Juelich kein C-Buch gibt...

immer wieder tauch so ein A... statt was helfen nur so was! klar 
bestimmt hat er selber keine Ahnung von C oder überhaupt aber Wichtig 
ist hier irgendwelche misst zu schreiben!

Gruß

von Urs (Gast)


Lesenswert?

> genauso effizient wie Makros

Das stimmt so nicht, weder bei der Ausführung, noch in der 
Programmierung.
Da Macros ja nur Textersetzungen sind, macht der Compiler keine 
Typumwandlungen. Bei Funktionen aber schon. Auch wenn man sie nicht 
braucht.
Wenn man Glück hat, haut's der Optimizer wieder raus. Es gibt da aber 
noch andere Sachen, da gehts einfach nicht.

Und das oben angegebene max() Macro kann man z.B. für jeden möglichen 
Datentyp, also ints, longs, shorts, quads, floats, doubles, singed oder 
unsigned, pointer (macht keinen Sinn, geht aber), usw. benutzen. Sogar 
Kombinationen sind möglich.

Davon mal abgesehen sind viele Dinge mit inlined functions schlichtweg 
unmöglich. Sogar mit C++ Templates. Wer Macros links liegen lässt, weil 
sie ihm zu gefährlich sind, der wird m.E. niemals effizient C/C++ 
programmieren lernen. Warum sind wohl die System headers alle voll mit 
Macros?

von Gast (Gast)


Lesenswert?

Hallo,
eine Delay Funktion würde ich sowieso als Funktion machen, da weiß man 
wie lange diese braucht, da der Datentyp in der Funktion fest ist.

Wenn du eine solche Funktion als MAKRO machst ist sie je nach Datentyp 
unterschiedlich langsam.

Angeommen du hast einen 8-Bit Controller:
1
#define DELAY(pause)do {\
2
  while(pause--)        \
3
} while(0)
4
5
...
6
unsigned char test1 = 100;
7
unsigned long test2 = 100;
8
9
DELAY(test1);  //braucht z.B. 100ms
10
DELAY(test2);  //braucht z.B. 400ms
11
...

von Karl H. (kbuchegg)


Lesenswert?

Urs wrote:

> Da Macros ja nur Textersetzungen sind, macht der Compiler keine
> Typumwandlungen. Bei Funktionen aber schon. Auch wenn man sie nicht
> braucht.

Das ist natürlich ein Argument. Stimme ich zu.

> Und das oben angegebene max() Macro kann man z.B. für jeden möglichen
> Datentyp, also ints, longs, shorts, quads, floats, doubles, singed oder
> unsigned, pointer (macht keinen Sinn, geht aber), usw. benutzen. Sogar
> Kombinationen sind möglich.

Yep. Und allen gemeinsam sind die Fallen die man damit stellt :-)
Man muss also immer abwägen was einem wichtiger ist: "code and forget" 
bei möglicherweise etwas verminderter Laufzeit (um die Aussage von oben 
'genauso effizient' etwas zu entschärfen) oder "code and remember what 
pitfalls are waiting" aber dafür am schnellsten.

> Davon mal abgesehen sind viele Dinge mit inlined functions schlichtweg
> unmöglich.

Yep. Alles was mit Token-pasting und concatination zu tun hat.

> Sogar mit C++ Templates. Wer Macros links liegen lässt, weil
> sie ihm zu gefährlich sind, der wird m.E. niemals effizient C/C++
> programmieren lernen. Warum sind wohl die System headers alle voll mit
> Macros?

Weil die Header uralt sind und sich noch niemand die Mühe gemacht hat 
sie auf inline umzuschreiben.
Behaupte ich jetzt mal.

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.