W całej naszej bazie kodu C widzę każde makro zdefiniowane w następujący sposób:
#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
Jakie jest uzasadnienie wykonywania tych kontroli definicji zamiast tylko definiowania makr?
#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
Nie mogę znaleźć wyjaśnienia tej praktyki w sieci.
c
macros
c-preprocessor
ifndef
Trevor Hickey
źródło
źródło
Odpowiedzi:
Pozwala to na przesłonięcie makr podczas kompilacji:
Definicje w pliku nagłówkowym są używane jako domyślne.
źródło
Jak powiedziałem w komentarzu, wyobraź sobie taką sytuację:
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; }
Wydrukuje
44
.Jeśli jednak warunek
ifndef
nie istnieje, wynikiem byłyby ostrzeżenia kompilacji o redefinicji MACRO i zostanie wydrukowane64
.$ 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 ^
źródło
ifdef
aby uniknąć ponownego zdefiniowania).#infdef
s są używane jako wartości „rezerwowe” lub „domyślne”. Zasadniczo, „jeśli użytkownik to skonfigurował, w porządku. Jeśli nie, użyjmy wartości domyślnej”.#defines
w bibliotece nagłówka, które są częścią ABI biblioteki, należy nie zawijać je#ifndef
. (Lub lepiej, użyjenum
). Chciałem tylko wyjaśnić, że#ifndef
jest to właściwe tylko wtedy, gdy posiadanie niestandardowej definicji czegoś w jednej jednostce kompilacji, a nie inna, jest w porządku. Jeślia.c
zawiera nagłówki w innej kolejności niżb.c
, mogą otrzymać inne definicjemax(a,b)
, a jedna z tych definicji może się zrywaćmax(i++, x)
, ale druga może używać tymczasowych w wyrażeniu-instrukcji GNU. Wciąż co najmniej zagmatwane!#ifdef FOO
#error FOO already defined!
#endif
#define FOO x
Nie znam kontekstu, ale można go użyć, aby dać użytkownikowi możliwość zastąpienia wartości ustawionych przez te definicje makr. Jeśli użytkownik wyraźnie zdefiniuje inną wartość dla któregokolwiek z tych makr, zostanie ona użyta zamiast użytych tutaj wartości.
Na przykład w g ++ możesz użyć
-D
flagi podczas kompilacji, aby przekazać wartość do makra.źródło
Odbywa się to po to, aby użytkownik pliku nagłówkowego mógł przesłonić definicje ze swojego kodu lub z flagi -D kompilatora.
źródło
Każdy projekt w języku C znajduje się w wielu plikach źródłowych. Podczas pracy z pojedynczym plikiem źródłowym sprawdzenia wydają się (i faktycznie) nie mają sensu, ale podczas pracy nad dużym projektem C dobrą praktyką jest sprawdzenie istniejących definicji przed zdefiniowaniem stałej. Pomysł jest prosty: potrzebujesz stałej w tym konkretnym pliku źródłowym, ale mogła być już zdefiniowana w innym.
źródło
Możesz pomyśleć o frameworku / bibliotece, która daje użytkownikowi domyślne ustawienie wstępne, które pozwala użytkownikowi na kompilację i pracę nad nim. Te definicje są rozmieszczone w różnych plikach, a końcowemu użytkownikowi zaleca się dołączenie swojego pliku config.h, w którym może skonfigurować jego wartości. Jeśli użytkownik zapomniał o jakimś zdefiniowaniu, system może kontynuować pracę z powodu ustawienia wstępnego.
źródło
Za pomocą
#ifndef BEEPTRIM_PITCH_RATE_DEGPS #define BEEPTRIM_PITCH_RATE_DEGPS 0.2f #endif
umożliwia użytkownikowi zdefiniowanie wartości makra za pomocą argumentu wiersza poleceń (w gcc / clang / VS)
-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f
.Jest jeszcze jeden ważny powód. Błędem jest ponowne definiowanie makra preprocesora w inny sposób. Zobacz tę odpowiedź na inne pytanie SO . Bez
#ifndef
sprawdzenia kompilator powinien wygenerować błąd, jeśli-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f
zostanie użyty jako argument wiersza polecenia w wywołaniu kompilatora.źródło