2015-09-04 10 views
89

Alle Basis für unsere C-Code, sehe ich jedes Makro folgendermaßen definiert:Warum nur ein Makro definieren, wenn es noch nicht definiert ist?

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

#ifndef BEEPTRIM_ROLL_RATE_DEGPS 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#endif 

#ifndef FORCETRIMRELEASE_HOLD_TIME_MS 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#endif 

#ifndef TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 
#endif 

Was ist der Grund diese definieren Kontrollen zu tun, die Makros, anstatt nur zu definieren?

#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#define BEEPTRIM_ROLL_RATE_DEGPS     0.2f 
#define FORCETRIMRELEASE_HOLD_TIME_MS    1000.0f 
#define TRIMSYSTEM_SHEARPIN_BREAKINGFORCE_LBS  50.0f 

Ich kann diese Praxis nirgends im Web erklärt finden.

+6

Das Ändern von Konstanten an anderer Stelle im Code funktioniert garantiert auf diese Weise. Wenn irgendwo jemand anderes eines dieser Makros definiert, werden diese beim Prägen dieser Datei nicht vom Präprozessor überschrieben. –

+8

Es ist ein Beispiel für das WET-Design-Prinzip. – stark

+0

Gebe eine Antwort mit einem Beispiel an, versuche es zu kompilieren. –

Antwort

132

Auf diese Weise können Sie die Makros außer Kraft zu setzen, wenn Sie kompilieren:

gcc -DMACRONAME=value 

Die Definitionen in der Header-Datei werden als Standard verwendet.

17

Ich kenne den Kontext nicht, aber dies kann verwendet werden, um dem Benutzer die Möglichkeit zu geben, die von diesen Makrodefinitionen festgelegten Werte zu überschreiben. Wenn der Benutzer explizit einen anderen Wert für eines dieser Makros definiert, wird er anstelle der hier verwendeten Werte verwendet.

Zum Beispiel können Sie in g ++ das Flag -D während der Kompilierung verwenden, um einen Wert an ein Makro zu übergeben.

14

Dies geschieht, damit der Benutzer der Header-Datei die Definitionen seines Codes oder des -D-Flags des Compilers überschreiben kann.

7

Jedes C-Projekt befindet sich in mehreren Quelldateien. Wenn Sie an einer einzelnen Quelldatei arbeiten, scheinen die Überprüfungen (und tatsächlich) keinen Sinn zu haben. Wenn Sie jedoch an einem großen C-Projekt arbeiten, sollten Sie nach vorhandenen Definitionen suchen, bevor Sie eine Konstante definieren. Die Idee ist einfach: Sie brauchen die Konstante in dieser spezifischen Quelldatei, aber sie wurde möglicherweise schon in einer anderen definiert.

51

Als ich im Kommentar sagte, sich vorstellen, diese Situation:

foo.h

#define FOO 4 

defs.h

#ifndef FOO 
#define FOO 6 
#endif 

#ifndef BAR 
#define BAR 4 
#endif 

bar.c

#include "foo.h" 
#include "defs.h" 

#include <stdio.h> 

int main(void) 
{ 
    printf("%d%d", FOO, BAR); 
    return 0; 
} 

Wird gedruckt 44.

Wenn jedoch die bedingte ifndef nicht dort war, würde das Ergebnis Kompilierung Warnungen MACRO Redefinition sein und es 64 drucken.

$ gcc -o bar bar.c 
In file included from bar.c:2:0: 
defs.h:1:0: warning: "FOO" redefined [enabled by default] 
#define FOO 6 
^ 
In file included from bar.c:1:0: 
foo.h:1:0: note: this is the location of the previous definition 
#define FOO 4 
^ 
+1

Dies ist Compiler-spezifisch. Die Neudefinition eines objektartigen Makros ist illegal, es sei denn, die Neudefinition ist "gleich" (es gibt eine technische Spezifikation dafür, aber hier ist es nicht wichtig). Illegaler Code erfordert eine Diagnose, und nachdem er eine Diagnose (hier eine Warnung) ausgegeben hat, ist der Compiler frei, alles zu tun, einschließlich des Kompilierens des Codes mit implementierungsspezifischen Ergebnissen. –

+7

Wenn Sie widersprüchliche Definitionen für das gleiche Makro haben, erhalten Sie dann in den meisten Fällen keine Warnung? Anstatt stillschweigend die erste Definition zu verwenden (weil die zweite einen 'ifdef' verwendet, um eine Neudefinition zu vermeiden). –

+0

@PeterCordes In den meisten Fällen werden Definitionen unter '# infdef' als" Fallback "- oder" Default "-Werte verwendet. Grundsätzlich, "wenn der Benutzer es konfiguriert, gut. Wenn nicht, verwenden wir einen Standardwert." – Angew

2

Man könnte denken über eine Rahmen/Bibliothek, die eine Standard-Voreinstellung für den Benutzer gibt, die dem Benutzer erlauben, auf ihn zu kompilieren und zu arbeiten. Diese Definitionen werden in verschiedenen Dateien verteilt und dem Endbenutzer wird empfohlen, seine config.h-Datei hinzuzufügen, wo er seine Werte konfigurieren kann. Wenn der Benutzer etwas vergessen hat, kann das System aufgrund des Presets weiter arbeiten.

1

Verwendung

#ifndef BEEPTRIM_PITCH_RATE_DEGPS 
#define BEEPTRIM_PITCH_RATE_DEGPS     0.2f 
#endif 

ermöglicht es dem Benutzer, den Wert des Makros zu definieren, mit dem Befehlszeilenargument (in gcc/Klappern/VS) -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f.

Es gibt einen anderen wichtigen Grund. Es ist ein Fehler, ein Präprozessor-Makro anders zu definieren. Siehe this answer to another SO question. Ohne die Überprüfung #ifndef sollte der Compiler einen Fehler erzeugen, wenn -DBEEPTRIM_PITCH_RATE_DEGPS=0.3f als ein Befehlszeilenargument im Compileraufruf verwendet wird.

Verwandte Themen