Warum Makros in C verwenden? [duplicate]

Lesezeit: 9 Minuten

Benutzeravatar von Alan Storm
Alan Sturm

Mögliches Duplikat:

Wofür sind C-Makros nützlich?

Alle paar Monate bekomme ich Lust, ein bisschen C zu lernen, das meine beschissene College-Programmierausbildung nie abgedeckt hat. Heute sind es Makros. Mein grundlegendes Verständnis von Makros ist, dass sie ein einfaches Suchen und Ersetzen sind, das in Ihrem Code stattfindet frühere dazu, dass es zusammengestellt wird. Ich habe Verständnisschwierigkeiten warum Sie würden Makros verwenden. Die meisten der grundlegenden Beispiele, die ich mir anschaue, sind so etwas wie

TEST(a,%d);
#define TEST(a,b) printf(" The value of " #a " = " #b " \n", a)

//which expands to 
printf(" The value of a = %d \n",a);

(Beispiel aus hier)

Aus meiner Sicht als Neuling scheint es, als würde die Definition einer neuen Funktion zu denselben Ergebnissen führen. Ich kann sehen, wie nützlich Makros in den Tagen vor dem einfachen Suchen und Ersetzen waren, um viele Quellen schnell zu ändern, aber etwas sagt mir, dass ich einen größeren Punkt übersehe.

Welche nützlichen Dinge können Makros also für Sie tun?

  • Die Verwendung von Makros auf die von Ihnen vorgeschlagene Weise (Ändern des vorhandenen Quellcodes durch Neudefinieren vorhandener Token, anstatt den Code tatsächlich zu ändern) ist eine wirklich schlechte Idee, es sei denn, Sie sprechen nur über das Ändern der Werte von #definierten Konstanten.

    – Tyler McHenry

    31. August 2009 um 16:53 Uhr

  • Dupe von stackoverflow.com/questions/653839/what-are-c-macros-useful-for unter vielen, vielen anderen.

    anon

    31. August 2009 um 17:01 Uhr

  • Sicherlich ähnlich wie diese Fragen, aber keine, die bei der Suche auftauchte, fragte direkt, was Makros überlegen macht, anstatt nur eine Funktion zu definieren, die die Arbeit für Sie erledigt. Ich bin viel glücklicher mit den Antworten hier als in diesem anderen Thread.

    – Alan Sturm

    31. August 2009 um 17:23 Uhr

  • Alle Antworten, die hier erscheinen, sind in ähnlichen Fragen zu Makros aufgetaucht – schließlich gibt es eine begrenzte Anzahl von Dingen, die Sie mit Makros tun können.

    anon

    31. August 2009 um 17:31 Uhr

  • Ich stimme Nils nicht zu. Kurzes Beispiel, dies ist der einzige Thread, in dem jemand bemerkt hat, dass Makros verwendet werden können, um die Erstellung eines neuen Stack-Frames zu vermeiden, eine Antwort, die zustande kam, weil der Kontext meiner Frage anders war als bei den anderen Fragen.

    – Alan Sturm

    31. August 2009 um 18:39 Uhr

Benutzeravatar von Tyler McHenry
Tyler McHenry

Es ist nicht genau Suchen und Ersetzen, es ist eine Token-Erweiterung. C-Makros sind das, was jede andere Art von Makro in der Computerwelt ist: eine Möglichkeit, etwas Kurzes und Einfaches zu schreiben und es automatisch in etwas Längeres und Komplizierteres umzuwandeln.

Ein Grund für die Verwendung von Makros ist die Leistung. Sie sind eine Möglichkeit, den Overhead von Funktionsaufrufen zu eliminieren, da sie im Gegensatz zum Schlüsselwort “inline”, das oft ignoriert wird, immer inline erweitert werden Hinweis zum Compiler und existierte (im Standard) vor C99 nicht einmal. Siehe zum Beispiel die FD_-Familie von Makros, die in Verbindung mit den von select und pselect verwendeten fd_sets verwendet werden. Diese fd_sets sind wirklich nur Bitsets, und die FD_-Makros verstecken Bit-Twiddling-Operationen. Es wäre ärgerlich, jedes Mal das Bit-Drehen selbst herauszuschreiben, und ein Funktionsaufruf wäre für eine so schnelle Operation viel Overhead, wenn er nicht inliniert wäre.

Außerdem können Makros einige Dinge tun, die Funktionen nicht können. Erwägen Sie das Einfügen von Token. Da der Präprozessor vor dem Compiler ausgeführt wird, kann er neue Bezeichner für den Compiler zur Verwendung erstellen. Dies kann Ihnen eine Kurzform geben, um viele ähnliche Definitionen zu erstellen, z

#define DEF_PAIR_OF(dtype) \
  typedef struct pair_of_##dtype { \
       dtype first; \
       dtype second; \
  } pair_of_##dtype##_t 

 DEF_PAIR_OF(int);
 DEF_PAIR_OF(double);
 DEF_PAIR_OF(MyStruct);
 /* etc */

Eine andere Sache, die eine Funktion nicht kann, ist die Umwandlung von Informationen zur Kompilierzeit in Laufzeitinformationen:

#ifdef DEBUG
#define REPORT_PTR_VALUE(v) printf("Pointer %s points to %p\n", #v, v)
#else 
#define REPORT_PTR_VALUE(v)
#endif

void someFunction(const int* reallyCoolPointer) {
  REPORT_PTR_VALUE(reallyCoolPointer);
  /* Other code */
}

Es gibt keine Möglichkeit, dass eine Funktion den Namen ihres Parameters in ihrer Ausgabe verwendet, wie es das Makro kann. Dies demonstriert auch das Kompilieren von Debug-Code für Release-Builds.

Ein Grund dafür ist, dass das Schlüsselwort inline bis C99 kein Standard in der Sprache C war. Makros ermöglichten es Ihnen also, kleine Funktionen einzubetten. Sie funktionieren auch in gewisser Weise wie Vorlagen, dh. Sie müssen keine Typen in der Makrodefinition angeben, z. B.:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

Dieses Makro ist kompatibel mit Ganzzahlen, Doubles, Floats usw.

  • Sie sollten Klammern um a und b auf der rechten Seite haben.

    – i_am_jorf

    31. August 2009 um 16:39 Uhr

  • Das ist ein guter Punkt. Makros erstellen keinen zusätzlichen Stapelrahmen (es sei denn, Sie rufen eine Funktion von einem auf).

    – Harfe

    31. August 2009 um 16:42 Uhr

  • Sind Inlines jetzt garantiert Inline?

    – Nosredna

    31. August 2009 um 16:53 Uhr

  • @Nosredna: Nein, sind sie nicht. In GCC nimmt der Compiler sie ohnehin als starken Hinweis, ignoriert Sie aber trotzdem, wenn er glaubt, es am besten zu wissen.

    – Mike McQuaid

    31. August 2009 um 16:54 Uhr

  • Mit dem Compiler von Microsoft können Sie __forceinline sagen, um den Compiler zu überschreiben. Aber Sie sollten es wahrscheinlich nie verwenden. Es sei denn, Sie sind die Art von Person, die sich die Demontage ansehen und mit Sicherheit sagen kann, dass einer besser ist als der andere. msdn.microsoft.com/en-us/library/z8y1yy88.aspx

    – i_am_jorf

    31. August 2009 um 17:33 Uhr

Makros werden zur Kompilierzeit erweitert. Sie haben Recht, dass sie oft missbraucht werden, aber ein klassisches Beispiel in C wäre ein Makro zum Schreiben von Debug-Meldungen, das (wenn der Debug-Modus zur Kompilierungszeit deaktiviert ist) keinen Code generiert und somit keine Verlangsamung verursacht.

  • “Makros werden zur Kompilierzeit erweitert.” Der Präprozessor erweitert Makros, bevor der Compiler überhaupt Code sieht.

    – Stil

    1. September 2011 um 16:56 Uhr

  • Dies ist ein Implementierungsdetail. Im Prinzip kann das als 2 Phasen der Kompilierung angesehen werden (und wenn wir genauer hinschauen, erledigt fast jeder echte Compiler die Arbeit in vielen Phasen unter der Haube).

    – Anzeigename

    13. März 2013 um 12:13 Uhr

Benutzeravatar von i_am_jorf
ich_am_jorf

Manchmal möchten Sie protokollieren, aber nur im Debug-Modus. Also schreibst du sowas wie:

#ifdef DEBUG
#define LOG_MSG(x) printf(x);
#else
#define LOG_MSG(X)
#endif

Manchmal möchten Sie einfach etwas basierend auf einem Schalter zur Kompilierungszeit ein- oder ausschalten. Beispiel: Mein Unternehmen führt ein Co-Branding unseres Produkts durch und Partner bitten darum, die Dinge abzuschalten. Also machen wir so etwas wie:

#ifndef SPECIAL_PARTNER_BUILD
    DoSomethingReallyAwesome();
#endif

Baue dann mit -DSPECIAL_PARTNER_BUILD, wenn du dem Partner Drops gibst.

Unter vielen anderen möglichen Gründen.

Manchmal möchten Sie sich nur das Tippen für Dinge ersparen, die Sie immer wieder tun. Manche Leute nehmen das zu weit (Husten MFC Husten) und schreiben in Makros, was auf ihre eigene Sprache hinausläuft, um eine schwierige API zu abstrahieren. Das macht das Debuggen zu einem Albtraum.

Makros können viele andere Verwendungen haben, abgesehen davon, dass sie wie Dinge funktionieren.

Es ist sehr nützlich, Makros für alles zu verwenden, was mit magischen Zahlen oder Zeichenfolgen zu tun hat.

#define MY_MAGIC_NUM 57

/*MY_MAGIC_NUM used all through out the code*/

  • So etwas kann die Lesbarkeit Ihres Codes erhöhen. Außerdem ist es ziemlich nützlich, wenn Sie die maximale Größe eines nicht auf dem Heap zugewiesenen Arrays definieren.

    – EM

    31. August 2009 um 16:53 Uhr

  • Warum wird dies der Verwendung einer Konstante vorgezogen?

    – Alan Sturm

    31. August 2009 um 16:55 Uhr

  • Warten Sie, streichen Sie das, ich habe gerade festgestellt, dass Konstanten Makros in C verwenden.

    – Alan Sturm

    31. August 2009 um 16:57 Uhr

  • Ein Array muss mit einem Kompilierzeit-Konstantenausdruck deklariert werden. Im Gegensatz zu C++ const in C ist niemals eine Kompilierzeitkonstante. (In C99 können Arrays innerhalb von Funktionen mit variabler Größe deklariert werden).

    – EM

    31. August 2009 um 17:05 Uhr

  • Nein, es gibt einen deutlichen Unterschied zwischen einer globalen konstanten Variablen und einem Makro. Der Wert des Makros wird nämlich vor der Kompilierung in den Code eingesetzt, während der Wert der globalen Konstante in der ausführbaren Datei gespeichert und in den Speicher geladen und zur Ausführungszeit abgerufen wird (ungeachtet der Optimierungen). Sie können die Adresse einer globalen Konstante nehmen, aber nicht die Adresse eines Makros.

    – Tyler McHenry

    31. August 2009 um 17:05 Uhr

C-Makros können zur Kompilierzeit Code generieren. Dies kann (missbraucht) werden, um effektiv domänenspezifische Sprachen mit neuen Schlüsselwörtern und Verhaltensweisen zu erstellen.

Eines meiner Lieblingsbeispiele ist die Methode von Simon Tatham Implementierung von Coroutinen in C über Makros. Das einfachste implementierte Makro ist:

#define crBegin static int state=0; switch(state) { case 0:

Ja, mit einer unübertroffenen Zahnspange. Andere Makros werden das beheben.

  • So etwas kann die Lesbarkeit Ihres Codes erhöhen. Außerdem ist es ziemlich nützlich, wenn Sie die maximale Größe eines nicht auf dem Heap zugewiesenen Arrays definieren.

    – EM

    31. August 2009 um 16:53 Uhr

  • Warum wird dies der Verwendung einer Konstante vorgezogen?

    – Alan Sturm

    31. August 2009 um 16:55 Uhr

  • Warten Sie, streichen Sie das, ich habe gerade festgestellt, dass Konstanten Makros in C verwenden.

    – Alan Sturm

    31. August 2009 um 16:57 Uhr

  • Ein Array muss mit einem Kompilierzeit-Konstantenausdruck deklariert werden. Im Gegensatz zu C++ const in C ist niemals eine Kompilierzeitkonstante. (In C99 können Arrays innerhalb von Funktionen mit variabler Größe deklariert werden).

    – EM

    31. August 2009 um 17:05 Uhr

  • Nein, es gibt einen deutlichen Unterschied zwischen einer globalen konstanten Variablen und einem Makro. Der Wert des Makros wird nämlich vor der Kompilierung in den Code eingesetzt, während der Wert der globalen Konstante in der ausführbaren Datei gespeichert und in den Speicher geladen und zur Ausführungszeit abgerufen wird (ungeachtet der Optimierungen). Sie können die Adresse einer globalen Konstante nehmen, aber nicht die Adresse eines Makros.

    – Tyler McHenry

    31. August 2009 um 17:05 Uhr

Benutzeravatar von jmq
jmq

Wir haben diese Art von Makro in unserem Code verwendet:

// convenience macros for implementing field setter/getter functions
#ifndef CREATE_GET_SET
#define CREATE_GET_SET(PREFIX, FIELD_NAME,FIELD_DATATYPE) \
  protected:\
    FIELD_DATATYPE PREFIX ## FIELD_NAME;\
  public:\
  inline FIELD_DATATYPE get ## _ ## FIELD_NAME(void) const\
  { \
    return(PREFIX ## FIELD_NAME); \
  } \
  inline void set ## _ ## FIELD_NAME(FIELD_DATATYPE p) \
  { \
    PREFIX ## FIELD_NAME = p; \
  }
#endif

Innerhalb einer Klasse/Struktur würden Sie eine Variable definieren:

CREATE_GET_SET(_, id, unsigned int);

Dies würde Ihre Variable definieren und den generischen Getter/Setter für den Code erstellen. Es sorgt nur für eine sauberere, konsistente Codegenerierung für get/set. Sicher, Sie können alles aufschreiben, aber das ist eine Menge Boilerplate-Code. HINWEIS: Dies ist nur eines von ein paar Makros. Ich habe nicht alle gepostet. Sie würden sagen “char *” nicht auf diese Weise behandeln (wo Sie möchten, dass der Satz die Daten strncpy oder strcpy löscht). Dies war nur eine einfache Demonstration dessen, was Sie mit einem Makro und einigen einfachen Typen tun können.

1410660cookie-checkWarum Makros in C verwenden? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy