Ist die Verwendung von C / C ++ - Makros als Verknüpfung für die bedingte Kompilierung eine gute Praxis?

13

Angenommen, ich möchte mehrere Arten von Ausgabenachrichten in meinem Code haben. Eine davon ist die DEBUG, die nur gedruckt wird, wenn der Code im Debug-Modus kompiliert wird.

Normalerweise müsste ich sowas schreiben

#ifdef DEBUG
    std::cout << "Debug message" << std::endl;
#endif

Das ist ziemlich umständlich und an vielen Stellen ärgerlich zu bedienen.

Ist es empfehlenswert, ein Makro für das Code-Snippet zu definieren, damit Sie es auf diese Weise verwenden können?

MSG_DEBUG("Debug message")

Oder gibt es eine andere, elegantere Möglichkeit, ohne Makros damit umzugehen? Ich interessiere mich für mögliche Lösungen in C und C ++, da ich beide Sprachen in verschiedenen Projekten verwende.

Eenoku
quelle
Aus der Frage, warum Sie nicht einfach den bedingten Code in eine Funktion einfügen und das aufrufen, ist nicht klar. Gibt es eine andere Einschränkung, die das verhindern würde?
Alex
@gnat Die Frage, die Sie angesprochen haben, ist so weit gefasst, dass die meisten Leute sie nicht mit diesem Thema in Verbindung bringen würden, besonders wenn sie diese spezielle Frage im Internet suchen würden.
Eenoku
3
Ihre Frage ist sowohl mit c als auch mit c ++ markiert , dies sind jedoch ziemlich unterschiedliche Sprachen. Können Sie klären, von welchem ​​Sie sprechen? Ihr Beispiel wäre in C vollkommen in Ordnung, könnte aber beispielsweise constexpr ifin C ++ besser implementiert werden .
Jörg W Mittag
1
Nebenbei sollte die Diagnose gehen STDERR. Warum sollte es nicht stattdessen von NDEBUGlike assert()does abhängen ? Dann könnte man es so definieren, dass es auch #define DEBUG_MSG(MSG) assert(std::cerr << MSG)den Stream-Status testet.
Deduplizierer

Antworten:

19

Wenn Sie in erster Linie Makros verwenden möchten, sollten Sie einen parametrisierten Code definieren, anstatt den gleichen bedingten Code zu wiederholen.

Sollten Sie überhaupt Makros verwenden? Meines Erachtens sollten Sie dies tun, da dies in C gängige Praxis ist und jede Lösung ohne Makros erfordert, dass zumindest etwas ausgeführt wird, auch außerhalb des Debug-Modus. Der typische C-Programmierer wählt zu jeder Zeit ein leicht hässliches Makro über unnötige Laufzeitbemühungen.

Kilian Foth
quelle
13

Hier gibt es ein persönliches Präferenzelement, aber in C ++ mache ich das lieber in der Header-Datei:

#ifdef _DEBUG
    void DebugMessage(...);
#else
    inline void DebugMessage(...) {}
#endif

Damit wird die Funktion in Release-Builds integriert, ist jedoch eine ordnungsgemäße Funktion im Debug-Build, sodass Sie später eine ordnungsgemäße Typprüfung, sinnvolle Fehlermeldungen usw. durchführen und weitere Funktionen (möglicherweise Protokollierung?) Hinzufügen können.

Offensichtlich müssen Sie auch die entsprechende Definition der Funktion in das .cpp Datei in einen #ifdef _DEBUGBlock einschließen.

Jack Aidley
quelle
Aber der Anrufoverhead ist hier immer noch vorhanden, nicht wahr?
Eenoku
7
Wenn Ihr Compiler Code generiert, um eine bekannte leere Funktion in einem Release-Build aufzurufen, müssen Sie zunächst einen viel besseren Compiler erstellen, um die Effizienz zu verbessern. Das ist wirklich eine triviale Optimierung.
David Thornley
@Eenoku Nein, wie David sagt, wird es von jedem Compiler entfernt, den Sie verwenden sollten.
Jack Aidley
3
Hier gibt es einen wesentlichen Unterschied: Das Makro (abhängig von seiner Schreibweise) würde seine Argumentausdrücke nicht auswerten, während die Funktion dies immer tun würde. Außerdem ist es undefiniert, nicht triviale Argumente an varargs-Funktionen zu übergeben (und löst normalerweise Compiler-Warnungen aus).
Sebastian Redl
2

Stellen Sie auf jeden Fall sicher, dass Sie nicht die von Ihrem Team vorgegebenen Code-Richtlinien befolgen. Stellen Sie sicher, dass kein anderer Code im System versucht, dieselbe Funktionalität über eine allgemeine if-Bedingung zu erreichen.

James O.
quelle