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?
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.
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!
> 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
voidwarte(){
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.
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...
@ 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!
@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?
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.
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?
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.
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
> 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...
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.
@ 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 );\
}
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
intWartezeit=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?
#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.
#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)
@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!
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 :-)
@... (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ß
> 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?
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:
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.