2010-01-18 11 views

Antwort

0

Dies ist gelegentlich nützlich in einer sehr geschlossenen Domäne zur Definition von Prozessschritten in einer besser lesbaren Art und Weise:

void myfunc() { 
    DO_STEP_ONE; 
    THEN_ANOTHER_STEP; 
    KEEP_GOING; 
    LAST_STEP; 
} 

Aber in der Regel macht es nur Code schwerer zu lesen und zu verstehen.

Wenn es den Lesern Ihres Codes nicht wert ist zu erfahren, was diese # define im Detail bedeuten, und es sich um eine Art Abkürzung handelt, erhalten Sie nur Leute, die an zwei Stellen nach einer Codezeile suchen von Datei und in Funktion) statt einer.

Ich verwende sehr selten diese Art von Ansatz.

+0

Verwendung von Makros für diese ist nicht mehr lesbar als Funktionen mit dem gleichen Namen – user463035818

0

Die von der Sprache abhängen, Compiler, etc, etc, etc ...

Allerdings gibt es nichts falsch mit ihm, sobald wie der Namen dieser Richtlinien treten zuvor den Prozess der Zusammenstellung impliziert.

Der Vorprozessor entfernt alle konstanten Referenzen durch seinen echten Wert, alle pseudo-Funktion mit dem richtigen Code, und so weiter ...

0

Alle Probleme in der Informatik kann durch einen anderen gelöst werden Niveau indirection

Dies ist einer dieser zusätzlichen Indirektion Ebenen :-)

sagen, dass irgendwann diese Funktion ein weiteres Argument benötigt oder Sie nicht brauchen Um es überhaupt aufzurufen, können Sie die #define einmal ändern, anstatt alle Stellen zu ändern, an denen die Funktion aufgerufen wird.

Nützlich für die Entwicklung, aber gefährlich, Produktionscode zu halten ... Ich würde den Präprozessor ausführen, um diese Regel zu ersetzen, sobald ich einen ausgereiften Code habe und weiß, dass ich ihn nicht ändern muss.

+0

Was zu vielen Dereferenzierungsebenen zu haben? ;) – daotoad

5

Ein Nachteil? Normalerweise endet eine Makrodefinition nicht in der Symboltabelle der ausführbaren Datei. Etwas schwieriger zu debuggen.

5

Das Problem ist, dass die Argumente sind neu = jedes Mal, wenn sie verwendet werden ausgewertet:

#define MIN(A,B) ((A) < (B))?(A):(B); 

Beachten Sie, dass ich in alle Argumente zu wickeln haben ‚(‘ ‚)‘ um sicherzustellen, dass der Ausdruck auswertet corectly . Aber was passiert, wenn wir das tun?

int s = MIN(++current,Max); 

Codierung Ich würde erwarten, dass der Strom einmal erhöht wird, bevor die Funktion aufgerufen wird.Aber weil es ein Makro ist es einmal im Test und ein zweites Mal erhöht wird, wenn es immer noch kleiner als Max

+0

Während dies in der Tat ein Nachteil von Makros ist, 'gcc' bietet * Compiler-spezifische * Erweiterungen, dies zu umgehen:' #define MIN (a, b) ({typeof (a) _a = (a); typeof (b) _b = (b); _a <_b? _a: _b;}) '. – kennytm

+0

@Kenny: Ihr Macro Foo ist besser als meins. Ich habe es versucht und es funktioniert. Obwohl es nicht so aussah, würde ich nicht denken, dass eine Aussage (Block) als Rvalue fungieren könnte. –

+0

@Kenny: Leider nicht einmal Erweiterung des gcc funktionieren würde, wenn 'MIN' auf Variablen genannt wurden, die zur Unzeit genannt wurden' _a' und '_b'. – jamesdlin

2

Es gibt mehrere Probleme, die Sie sich vorstellen können:

  • In C++ Makro hat keine Namespace und Klassenraum, so ist es überall gleich. Ein Beispiel dafür sind die unglücklichen Min und Max definiert irgendwo in windows.h. Wenn Sie für Windows programmieren und windows.h einschließen und std :: numeric_limits :: max() schreiben wollen, dann wird max durch einen Code ersetzt ... Das lässt nach dem Präprozessor-Lauf einen nicht kompilierbaren Code übrig. (Okay, es gibt Möglichkeiten, Min-/Max-Makros in windows.h auszuschalten, aber es ist immer noch ein schlechtes Design!)
  • Das Makro nicht gut ausgetestet werden kann. Der Debugger wird auf der Linie stoppt das Makro verwendet wird, nicht auf dem Code innerhalb der Makro ...
  • Mögliche Umwertung des Makroparameters (Sie dies verhindern könnten einen Block mit lokalen Variablen innerhalb des Makro, indem aber das Debuggen machen würde noch schlimmer!)
0

Warum würden Sie nach Nachteilen bei der Verwendung von spezifischen Präprozessorcode suchen? Die Verwendung von Präprozessor-Makros für alles andere als die bedingte Kompilierung (einschließlich der eingeschlossenen Wächter) sollte automatisch als schlecht angesehen werden. Die richtige Frage ist, ob es Vorteile für eine bestimmte Verwendung gibt.

Präprozessormakros Umfang oder Nutzung nicht in irgendeiner Weise respektieren. Sie können perfekt guten Code auf unerwartete und schwer zu findende Weise vermasseln. Vermeide sie immer, es sei denn, du hast einen guten Grund, einen zu benutzen.

1

Nun, wenn Sie das tun müssen (und es gibt einige Gelegenheiten, bei denen Sie vielleicht), dann sollten Sie zumindest das Makro als „funktionsähnliche“ so definieren:

#define SOME_FUNCTION() someFunction(defaultArgument) 

sonst würden Sie Code schreiben, sah aus wie eine Zuweisung durch eine Konstante, wenn es sich tatsächlich um einen Funktionsaufruf handelte; d.

x = SOME_FUNCTION ; // hidden function call 

aber mit einer „funktionsähnlichen“ Makro, das Sie zu schreiben dazu verpflichtet wäre: mit der Sprachsyntax

x = SOME_FUNCTION() ; // shorthand function-call with default argument 

Welche bessere Matches der Vorprozessor Syntax.

allgemeinen Funktionsmakros am besten vermieden werden, aber einige sind heimtückisch, dass andere, ist dies keineswegs den schlimmsten Fall. Sie können jedoch genauso einfach einen Funktions-Wrapper in C schreiben oder in C++ ein Standardargument verwenden, was in den meisten Fällen vorzuziehen wäre.

0

Der Nachteil ist, dass Sie den Code versteckt. Der Vorteil ist, dass Sie den Code verstecken.

Der Nachteil überwiegt normalerweise die Oberseite.

Normalerweise ist dieser besondere Ansatz ist ziemlich nutzlos und es sei denn, der Anruf sieht eher aus wie

someModule-> someStorage-> Function [storage.getFunctionName] .pointer-> Funktion (... ebenso obskuren Argument ...);

es keinen Sinn, dies zu tun. Wenn nur das Argument ein obskurer Aufruf ist, schreiben Sie nur das Argument kurz. Wenn es nur die Funktion ist, schreiben Sie nur die Funktion kurz.Wenn beide, könnten Sie besser dran mit

SOME_FUNCTION(SOME_ARGUMENT); 

Wenn die Funktion nie sonst mit etwas genannt wird, könnten Sie es aus Argumentliste zu entfernen und im Funktionskörper zu erhalten. Und wenn sich das Paar sehr oft in kleinen Variationen wiederholt, könnten Sie Wrapper-Funktionen in Erwägung ziehen.

Nachdem Sie mehrere Fehler im Code eines Makros machen, werden Sie lernen, es Schmerz ist, sie zu debuggen und Sie werden sie nicht leichtfertig verwenden.

Verwandte Themen