Wofür sind C-Makros nützlich?
Ich geschrieben habe ein wenig Cund Lesen kann ich es gut genug, um eine Allgemeine Vorstellung von dem, was es tut, aber jedes mal, wenn ich begegnet bin, ein makro-es hat mich völlig geworfen. Ich habe bis zum Ende daran erinnern, was das makro ist und ersetzen Sie es in meinem Kopf, wie ich gelesen habe. Diejenigen, die mir begegnet, die waren intuitiv und einfach zu verstehen waren immer so kleine mini-Funktionen, so dass ich mich immer gefragt, warum Sie waren nicht nur Funktionen.
Kann ich verstehen, die Notwendigkeit zu definieren, die verschiedenen Bau-Typen, die für debug-oder cross-Plattform baut der Präprozessor aber die Fähigkeit zu definieren, die beliebige Substitution scheint sinnvoll zu sein, nur um eine bereits schwierige Sprache noch schwieriger zu verstehen.
Warum wurde so ein Komplexes Präprozessor eingeführt für C? Und hat jemand ein Beispiel für die Verwendung von es, wird mich verstehen, warum es scheint immer noch verwendet werden für andere Zwecke als einfach, wenn #debug-Stil conditional compilations?
Edit:
Gelesen hatte, eine Reihe von Antworten, die ich eben noch nicht bekommen. Die häufigste Antwort ist der inline-code. Wenn die inline-Schlüsselwort es nicht tut, dann hat Sie entweder einen guten Grund, um es nicht tun, oder die Umsetzung muss repariert werden. Ich verstehe nicht, warum ein ganz anderer Mechanismus erforderlich ist, das bedeutet "wirklich inline diesem code" (neben der form der code geschrieben wird, bevor die inline-war rund). Ich versteh auch nicht die Idee, dass erwähnt wurde, dass "wenn Ihr zu dumm zu sein, setzen in einer Funktion". Sicherlich irgendein Stück code, der nimmt eine Eingabe und produziert eine Ausgabe am besten in eine Funktion. Ich glaube, ich kann nicht, denn ich bin nicht verwendet, um die micro-Optimierungen zu schreiben Caber der Präprozessor fühlt sich einfach wie eine komplexe Lösung, um ein paar einfache Probleme.
InformationsquelleAutor der Frage Jack Ryan | 2009-03-17
Du musst angemeldet sein, um einen Kommentar abzugeben.
Scheint zu reflektieren, die schlecht auf die Benennung der Makros. Ich würde annehmen, die Sie nicht haben, zu emulieren, die Präprozessor, wenn es ein
log_function_entry()
makro.In der Regel sollten Sie, wenn Sie brauchen, um zu funktionieren auf generischen Parameter.
arbeiten auf jede Art mit einem
<
Betreiber.Mehr, dass nur Funktionen, Makros ermöglichen die Durchführung von Operationen mithilfe der Symbole, die in der Quell-Datei. Das heißt, Sie können eine neue variable erstellen namens, oder einen Verweis auf die Quelldatei und die Zeilennummer ist das makro auf.
Im C99-Makros können Sie auch anrufen variadischen Funktionen wie printf
In denen das format funktioniert wie printf. Wenn der guard wahr ist, gibt es die Nachricht zusammen mit der Datei und der Zeilennummer, druckte die Meldung. Wenn es eine Funktion nennen, wäre es nicht wissen, die Datei und die Zeile, die Sie genannt wird, und mit einem
vaprintf
wäre ein bisschen mehr Arbeit.InformationsquelleAutor der Antwort Pete Kirkham
Dieser Auszug ziemlich viel fasst meine Sicht der Dinge, durch den Vergleich von mehreren Möglichkeiten, die
C
Makros verwendet werden, und wie Sie Sie implementieren können, inD
.kopiert aus DigitalMars.com
Makros
Präprozessor-Makros fügen Sie leistungsfähige Funktionen und Flexibilität, um
C
. Aber Sie haben einen Nachteil:#include
'ing Zehntausende von Zeilen-makro-Definitionen, wird es problematisch, um nicht versehentlich makro-Erweiterungen.C++
.)Hier ist eine Aufzählung der häufigsten Verwendungszwecke für Makros, und die entsprechende Funktion in D:
Definition der literalen Konstanten:
Den
C
Präprozessor WegDen
D
WegErstellen Sie eine Liste der Werte oder flags:
Den
C
Präprozessor WegDen
D
WegEinstellung Funktion Aufrufkonventionen:
Den
C
Präprozessor WegDen
D
WegAufrufkonventionen kann angegeben werden, in Blöcken, so dass es keine Notwendigkeit gibt, ändern Sie es für jede Funktion:
Einfache generische Programmierung:
Den
C
Präprozessor WegAuswählen, welche Funktion zu verwenden, basierend auf dem text-Ersetzung:
Den
D
WegD
ermöglicht die Erklärungen der Symbole, sind Aliase für andere Symbole:Gibt es weitere Beispiele für die DigitalMars website.
InformationsquelleAutor der Antwort Brad Gilbert
Sind Sie mit einer Programmiersprache (eine einfachere) auf der Spitze von C, so sind Sie nützlich für das tun metaprogramming in compile-Zeit... in anderen Worten, Sie können makro schreiben code, der erzeugt C-code in weniger Zeilen und die Zeit, die es dauern wird, schreiben Sie es direkt in C.
Sind Sie auch sehr nützlich, um zu schreiben "- Funktion wie" Ausdruck "polymorph" oder "überlastet"; z.B. max-makro definiert als:
ist nützlich für jeden numerischen Typ; und in C könnte man nicht schreiben:
selbst wenn Sie wollte, weil Sie sich nicht überlasten Funktionen.
Und nicht zu vergessen die bedingte compilieren und die Datei darunter (die sind auch Teil der makro-Sprache)...
InformationsquelleAutor der Antwort fortran
Makros zulassen, jemand zu ändern, das Verhalten des Programms während der Kompilierung. Bedenken Sie:
Bei der Kompilierung bedeutet, dass nicht verwendete code wird nicht gehen sogar in die binäre und, dass der build-Prozess kann die Werte ändern, solange es mit dem integrierten makro-Präprozessor. Beispiel: make ARCH=arm (übernimmt die Weiterleitung makro-definition als cc -DARCH=arm)
Einfache Beispiele:
(von glibc Grenzen.h definieren Sie den größten Wert der long)
Überprüft (mithilfe der #define __WORDSIZE) zur compile-Zeit, wenn wir kompilieren für 32 oder 64 bit. Mit ein multilib-toolchain, mit Parameter -m32 und -m64 können automatisch ändern von bit-Größe.
(POSIX-version anfordern)
Anfragen während der Kompilierung POSIX 2008 unterstützen. Die standard-Bibliothek kann Unterstützung viele (inkompatible) standards, aber mit dieser definition, es wird die richtige Funktion Prototypen (Beispiel: getline(), keine bekommt(), etc.). Wenn die Bibliothek nicht die Unterstützung der standard-es kann ein #Fehler während der Kompilierung, statt Absturz während der Ausführung, zum Beispiel.
(hardcoded Pfad)
Definiert, die während der Kompilierung ein hardcode-Verzeichnis. Könnte geändert werden -DLIBRARY_PATH=/home/user/lib, zum Beispiel. Wenn das ein const char *, wie würden Sie es konfigurieren, die während der Kompilierung ?
(pthread.h, komplexe Definitionen zur compile-Zeit)
Große Stücke von text können, sonst würde nicht vereinfacht werden, erklärt werden können (immer zur compile-Zeit). Es ist nicht möglich, mit Funktionen oder Konstanten (zur compile-Zeit).
Zu vermeiden, wirklich zu verkomplizieren und zu vermeiden, was darauf hindeutet, schlechte coding styles, ich bin nicht geben Sie ein Beispiel für code, kompiliert in verschiedene, inkompatible Betriebssysteme. Verwenden Sie Ihre cross-build-system, aber es sollte klar sein, dass der Präprozessor ermöglicht es, dass ohne die Hilfe aus dem build-system, ohne zu brechen Zusammenstellung aufgrund fehlender Schnittstellen.
Schließlich denke, über die Bedeutung der bedingten Kompilierung auf eingebetteten Systemen, wo die Prozessor-Geschwindigkeit und Speicher sind begrenzt, und die Systeme sind sehr heterogen.
Wenn Sie jetzt Fragen, ist es möglich, zu ersetzen Sie alle makro-Konstanten-Definitionen und Funktionsaufrufe mit der richtigen Definitionen ? Die Antwort ist ja, aber es wird nicht einfach nur die Notwendigkeit, sich verändernden Verhalten des Programms während der Kompilierung Weg. Der Präprozessor würde noch benötigt werden.
InformationsquelleAutor der Antwort hdante
Denken Sie daran, dass die Makros (und die pre-Prozessor) stammen aus den frühesten Tagen von C. Sie verwendet werden, um NUR so zu tun inline "Funktionen" (weil, natürlich, inline ist ein sehr Aktuelles Stichwort), und Sie sind immer noch der einzige Weg zu ZWINGEN, etwas zu werden inlined.
Außerdem sind die Makros nur so kann man solche tricks wie das einfügen der Datei und Zeile, in string-Konstanten, die zur compile-Zeit.
Diesen Tagen, viele der Dinge, die Makros verwendet werden, die nur so tun, werden besser behandelt, durch neue Mechanismen. Aber Sie haben immer noch Ihren Platz, von Zeit zu Zeit.
InformationsquelleAutor der Antwort Michael Kohne
Abgesehen von inlining für Effizienz und bedingte Kompilierung, Makros können verwendet werden, um die Abstraktionsebene der low-level C code. C nicht wirklich isolieren Sie von der nitty-gritty details des Speicher-und Ressourcen-management und die genaue layout-Daten, und unterstützt sehr eingeschränkte Formen von information hiding und andere Mechanismen für die Verwaltung von großen Systemen. Mit Makros, sind Sie nicht mehr beschränkt auf die Verwendung nur die Basis-Konstrukte in die Sprache C: definieren Sie Ihre eigenen Daten, Strukturen und Codierung der Konstrukte (einschließlich der Klassen und Vorlagen!) während immer noch nominell schreiben von C!
Präprozessor-Makros bieten eigentlich eine Turing-vollständige Sprache ausgeführt zur compile-Zeit. Eine der beeindruckenden (und etwas beängstigend) Beispiele über auf der C++ Seite: die Boost Preprocessor Bibliothek verwendet das C99/C++98 Präprozessor zu bauen ist (relativ) sichere Programmierung Konstrukte, die dann erweitert, um was auch immer zugrunde liegende Deklarationen und code, die Sie eingeben, ob C oder C++.
In der Praxis, würde ich empfehlen, über Präprozessor-Programmierung als letzten Ausweg, wenn Sie nicht über die Breite zum Einsatz von high-level-Konstrukte in Sprachen sicherer. Aber manchmal ist es gut zu wissen, was Sie tun können, wenn Ihr Rücken ist gegen die Wand und das Wiesel Holen...!
InformationsquelleAutor der Antwort Pontus Gagge
Vom Computer Dummheiten:
Das ist nur eine mögliche Verwendung von Makros.
InformationsquelleAutor der Antwort Niet the Dark Absol
Einen der Fall, in denen Makros wirklich glänzen ist, wenn dabei die code-Generierung mit Ihnen.
Ich verwendet, um arbeiten an einem alten C++ - system mit einem plugin-system, mit seinen eigenen Weg, um Parameter an das plugin (unter Verwendung einer benutzerdefinierten map-Struktur). Einige einfache Makros, die verwendet wurden, um in der Lage sein, sich mit dieser Eigenart und erlaubt uns, verwenden Sie echte C++ - Klassen und Funktionen mit den normalen Parametern des plugins, ohne zu viel Probleme. Alle glue-code erzeugt durch Makros.
InformationsquelleAutor der Antwort Julien Roncaglia
Werde ich hinzufügen, was bereits gesagt worden ist.
Weil Makros funktionieren auf text-Ersetzungen erlauben Sie tun, sehr nützliche Dinge, die nicht möglich wäre, zu tun, mit Funktionen.
Hier ein paar Fälle, in denen Makros können sehr nützlich:
Dies ist eine sehr beliebte und Häufig verwendete makro. Dies ist sehr praktisch, wenn Sie zum Beispiel brauchen zum Durchlaufen eines Arrays.
Hierbei ist es egal, wenn ein anderer Programmierer fügt fünf weitere Elemente zu
a
in der Unabhängigkeitserklärung. Diefor
-Schleife wird immer iterieren durch alle Elemente.Die C-Bibliothek, die Funktionen zu vergleichen, Speicher und strings ziemlich hässlich zu verwenden.
Schreiben Sie:
oder
Um zu überprüfen, ob
str
Punkte zu"Hello, world"
. Ich persönlich denke, dass beide diese Lösungen sehen ziemlich hässlich und unübersichtlich (vor allem!strcmp(...)
).Hier sind zwei nette Makros einige Leute (darunter auch ich) verwenden, wenn Sie benötigen, um Zeichenketten miteinander zu vergleichen oder Speicher mit
strcmp
/memcmp
:Jetzt kannst du den code schreiben, wie diese:
Hier wird die Absicht viel klarer!
Diese Fälle wurden Makros werden verwendet, für Dinge, die Funktionen nicht erfüllen können. Makros sollten nicht verwendet werden, zu ersetzen-Funktionen, aber Sie haben andere gute Zwecke.
InformationsquelleAutor der Antwort wefwefa3
Angesichts der Kommentare, die in Ihrer Frage, Sie können nicht vollständig schätzen ist, dass Sie eine Funktion aufrufen, können Sie mit einem fairen Betrag von overhead. Die Parameter und Schlüssel registriert haben können kopiert werden, um die Stapel auf dem Weg, und der Stapel, schlängelte sich auf dem Weg nach draußen. Dies war vor allem auf die älteren Intel-chips. Makros lassen sich die Programmierer halten die Abstraktion von einer Funktion (fast), aber vermeiden Sie den teuren overhead eines Funktionsaufrufs. Das inline-Schlüsselwort ist eine beratende, aber der compiler kann nicht immer get es richtig. Der Ruhm und die Gefahr von 'C' ist, können Sie in der Regel biegen Sie den compiler, um deinen Willen.
In Ihrem Brot-und-butter -, Tag-zu-Tag-Anwendung, Programmierung, diese Art von Mikro-Optimierung (Vermeidung von Funktionsaufrufen) ist in der Regel schlimmer als nutzlos, aber wenn Sie schreiben eine Zeit-kritische Funktion, die aufgerufen wird, indem der kernel eines Betriebssystems, dann kann es einen großen Unterschied machen.
InformationsquelleAutor der Antwort Charles E. Grant
Im Gegensatz zu normalen Funktionen, die Sie tun können, Ablaufsteuerung (if, while, for,...) in Makros. Hier ist ein Beispiel:
InformationsquelleAutor der Antwort alexpinho98
Durch die Nutzung von C-Präprozessor-der text-manipulation kann man konstruieren, das C-äquivalent zu einer polymorphen Datenstruktur. Mit dieser Technik können wir konstruieren eine zuverlässige toolbox-primitive Datenstrukturen, die verwendet werden kann in jedem C-Programm, denn Sie nehmen Vorteil der C-syntax und nicht die Besonderheiten einer bestimmten Implementierung.
Detaillierte Erklärung, wie Sie die Makros verwenden, die für die Verwaltung der Struktur der Daten ist hier gegeben - http://multi-core-dump.blogspot.com/2010/11/interesting-use-of-c-macros-polymorphic.html
InformationsquelleAutor der Antwort coredump
Ist es gut für die inlining-code und die Vermeidung von function-call overhead. Sowie Sie es, wenn Sie wollen, ändern Sie das Verhalten später ohne Bearbeitung vielen Orten. Es ist nicht sinnvoll, für komplexe Dinge, aber für einfache code-Zeilen, die Sie wollen, inline, es ist nicht schlecht.
InformationsquelleAutor der Antwort Arkaitz Jimenez
Makros können Sie loszuwerden, kopieren-einfügen-Fragmente, die Sie nicht beseitigen können, die in irgendeiner anderen Weise.
Zum Beispiel (der code, der syntax von VS 2010 compiler):
Dies ist der Ort, wo Sie übergeben Sie einen Wert im Feld unter dem gleichen Namen in eine Skript-engine. Ist das kopieren-einfügen? Ja.
DisplayName
wird als string verwendet, um ein Skript und ein Feld name für den compiler. Ist das schlimm? Ja. Wenn Sie überarbeiten Sie den code und umbenennenLocalName
zuRelativeFolderName
(so wie ich) und vergessen, das gleiche zu tun mit der Zeichenfolge (wie ich), wird das script funktioniert in einer Weise, die Sie nicht erwarten, dass (in der Tat, in meinem Beispiel hängt es davon ab hast du vergessen zu benennen Sie das Feld in eine separate Skript-Datei, aber wenn das Skript verwendet für die Serialisierung, wäre es ein 100% bug).Wenn Sie ein makro verwenden, für diese, wird es keinen Raum für Fehler:
Leider, dies öffnet die Tür für andere Arten von bugs. Sie können einen Tippfehler schreiben Sie das makro, und wirst nie sehen, ein verzogener code, da der compiler nicht zeigen, wie es aussieht nach all der Vorverarbeitung. Jemand anders könnte den gleichen Namen verwenden (das ist, warum ich "release" Makros so schnell wie möglich mit
#undef
). Also, verwenden Sie es mit bedacht aus. Wenn Sie sehen, ein anderer Weg, um loszuwerden, kopieren-einfügen von code (z.B. Funktionen), verwenden Sie das Weg. Wenn Sie sehen, dass loswerden von kopieren-einfügen-code mit Makros ist es nicht Wert das Resultat, halten Sie die kopieren-einfügen-code.InformationsquelleAutor der Antwort noober
Einer der offensichtlichen Gründe ist, dass durch die Verwendung eines makro, den code erweitert werden, die zur compile-Zeit, und Sie bekommen eine pseudo-Funktion-Anruf ohne call-overhead.
Andernfalls können Sie es auch verwenden, um symbolische Konstanten, so dass Sie nicht haben, um zu Bearbeiten den gleichen Wert an mehreren stellen zu ändern, eine kleine Sache.
InformationsquelleAutor der Antwort sykora
Makros .. wenn Ihr &#(*$& compiler nur verweigert inline etwas.
Sollte das ein Motivations-poster, nicht?
Allen ernstes, google Präprozessor-Missbrauch (Sie können sehen, eine ähnliche Frage ALSO, wie die #1 Ergebnis). Wenn ich Schreibe ein makro, das geht über die Funktionalität von assert(), ich in der Regel versuchen, um zu sehen, ob mein compiler würde tatsächlich inline eine ähnliche Funktion.
Andere argumentieren gegen die Verwendung von #if für bedingte Kompilierung .. eher würden Sie Sie:
eher als
.. für debugging-Zwecke, da Sie können finden Sie in der wenn () - aber nicht #wenn Sie in einer debugger. Dann Tauchen wir in die #ifdef vs #wenn.
Wenn Ihr unter 10 Zeilen code, versuchen, inline es. Wenn es nicht inlined, versuchen, es zu optimieren. Wenn es zu albern zu werden, eine Funktion, ein makro machen.
InformationsquelleAutor der Antwort Tim Post
Während ich nicht bin ein großer fan von Makros und nicht dazu neigen viel zu schreiben C mehr, basierend auf meinen aktuellen tasking, so etwas wie dieses (und das kann offensichtlich haben einige Nebenwirkungen) ist bequem:
Nun ich habe nicht geschrieben, so etwas wie, dass in Jahren, sondern "Funktionen" wie, die waren alle über code, ich hielt früher in meiner Karriere. Ich denke, die Erweiterung könnte als bequem.
InformationsquelleAutor der Antwort itsmatt
Ich niemanden sehen denen dieses also, in Bezug auf funktionieren wie Makros, zB:
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
In der Regel, es ist empfohlen zu vermeiden, mit Makros, wenn Sie nicht notwendig, für viele Gründe, die Lesbarkeit, die wichtigsten Anliegen. Also:
Fast nie, da gibt es eine besser lesbare alternative, die
inline
finden Sie https://www.greenend.org.uk/rjk/tech/inline.htmloder http://www.cplusplus.com/articles/2LywvCM9/ (der zweite link ist ein C++ - Seite, aber der Punkt gilt für c-Compiler soweit ich weiß).
Nun, der kleine Unterschied ist, dass die Makros behandelt werden, die von der pre-Prozessor und inline erfolgt durch den compiler, aber es gibt keinen praktischen Unterschied heutzutage.
Für kleine Funktionen (zwei oder drei Zwischenlagen max.). Das Ziel ist, zu gewinnen einen Vorteil während der Laufzeit eines Programms, wie funktionieren wie Makros und inline-Funktionen) sind code-Ersetzungen durchgeführt, während der pre-Verarbeitung (oder Kompilierung im Fall von inline -) und sind keine echten Funktionen Leben im Speicher, so dass es keine Funktionsaufruf-overhead (mehr details in den verlinkten Seiten).
InformationsquelleAutor der Antwort äli