Wie schreibe ich ein einfaches Makro in C?

#1189302
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?
#1189459
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.
Persönliche Seite #1189503
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.
#1189515
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...
#1189524
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!
Moderator (Firma: Titel) Persönliche Seite #1189550
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?
#1189551
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.
#1189556
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 :-)
Gast #1189562
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...
#1189581
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.
#1189602
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?
Gast #1189608
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.
#1189629
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!
Gast #1189678
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?
Gast #1189679
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
...
#1189692
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren