2013-03-16 4 views
7

Was ist eine versehentliche Makrosubstitution?Was ist eine versehentliche Makrosubstitution?

In Vera++ C++ Linter, Regel T016 heißt es:

Die Anrufe auf min und max-Funktionen sollten gegen versehentliche Makroersetzung geschützt werden.

x = max(y, z); // wrong, vulnerable to accidental macro substitution 

x = (max)(y, z); // OK 

x = max BOOST_PREVENT_MACRO_SUBSTITUTION (y, z); // OK 

Warum ist das eine gute Regel, und was ist das Besondere an Min- und Max-Funktionen, die diese Regel benötigen?

Antwort

8

Eine versehentliche Makrosubstitution ist eine unbeabsichtigte Verwendung eines Makros, dessen Name mit einer Funktion in Konflikt steht.

Die Situation Vera ++ 's Kontrollen ausgelegt tritt zu verhindern, wenn System-Header misbehaved - am bekanntesten <windows.h> - definieren min und max Makros, die mit der Anwendung definierte Funktionen mit dem gleichen Namen oder sogar mit Standard-Bibliotheksfunktionen wie std::min<T>, std::max<T> stören, und std::numeric_limits<T>::min(). (Andere Namen wurden bekannt Auseinandersetzungen auch verursachen.)

Da Makros werden Namespace-aware, die Funktionen als std::min(...) Aufruf hilft nicht, weil min noch durch den Präprozessor erweitert wird. Um dieses Problem zu umgehen, müssen solche Funktionen als (function)(args...) aufgerufen werden, wodurch eine Makroexpansion verhindert wird, vorausgesetzt, sie ist als #define function(arg1, arg2) ... definiert, wie dies typischerweise bei min und max der Fall ist. Eine andere verfügbare Option ist #undef sie vor der Verwendung, aber nach dem Einfügen der fehlerhaften Header. Boost bietet seinen eigenen Substitutionspräventions-Marker, obwohl seine Selbstbeschreibungsfähigkeit durch die Unordnung, die es einführt, aufgewogen wird.

Wenn Sie die Aufnahme von <windows.h> steuern, können Sie auch #define NOMINMAX vor der Aufnahme, die instruiert windows.h nicht die min und max Makros zu definieren.

+0

+1. Völlig unabhängig von dem, was ich ursprünglich für die Frage hielt. Es gibt ein paar andere davon außer Min und Max, soweit ich mich erinnere. – WhozCraig

+0

BOOST_PREVENT_MACRO_SUBSTITUTION ist nur "#define BOOST_PREVENT_MACRO_SUBSTITUTION" (es ist kein Wert definiert). Es ist nur unlesbar, weil sie einen beschreibenden Namen für das Makro auswählen. –

+0

'#define NOMINMAX' hilft auch. – chris

0

Das Problem ist, dass bösartige Bibliotheken (oder dumme Programmierer) häufig max und min Makros definieren, die Sie möglicherweise nicht erwarten. Wenn Ihr Code davon ausgeht, dass die Auswertung durch eine nette Funktion ausgeführt wird, erhalten Sie falsche Ergebnisse (oder sogar undefiniertes Verhalten). Der Linter ist hilfreich, indem er darauf hinweist, dass es sicherer ist, wenn Sie nicht wirklich sicher sind, alle Makros zu kennen, die von allen Includes definiert werden, die Sie verwenden, um nicht mit solchen allgemeinen Makronamen zu kollidieren.