Я вижу, что во всей нашей базе кода C каждый макрос определяется следующим образом:
#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
В чем смысл выполнения этих проверок определения вместо простого определения макросов?
#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
Я не могу найти объяснения этой практики в Интернете.
c
macros
c-preprocessor
ifndef
Тревор Хики
источник
источник
Ответы:
Это позволяет вам переопределить макросы при компиляции:
Определения в файле заголовка используются по умолчанию.
источник
Как я сказал в комментарии, представьте себе такую ситуацию:
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; }
Распечатаю
44
.Однако, если бы условия
ifndef
не было, результатом будет предупреждение компиляции о переопределении MACRO, и оно будет напечатано64
.$ 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 ^
источник
ifdef
чтобы избежать переопределения).#infdef
s используются как «резервные» или «значения по умолчанию». По сути, «если пользователь настроил это, хорошо. Если нет, давайте использовать значение по умолчанию».#defines
в заголовке библиотеки, которые являются частью ABI библиотеки, вам не следует их оборачивать#ifndef
. (Или лучше использоватьenum
). Я просто хотел прояснить, что#ifndef
это уместно только тогда, когда пользовательское определение чего-то в одной единице компиляции, но не в другой, нормально. Еслиa.c
заголовки включены в другом порядкеb.c
, они могут получить разные определенияmax(a,b)
, и одно из этих определений может нарушитьсяmax(i++, x)
, но другое может использовать временные элементы в выражении оператора GNU. По крайней мере, все еще сбивает с толку!#ifdef FOO
#error FOO already defined!
#endif
#define FOO x
Я не знаю контекста, но это можно использовать, чтобы дать пользователю возможность переопределить значения, установленные этими определениями макросов. Если пользователь явно определяет другое значение для любого из этих макросов, оно будет использоваться вместо значений, используемых здесь.
Например, в g ++ вы можете использовать
-D
флаг во время компиляции для передачи значения макросу.источник
Это сделано для того, чтобы пользователь файла заголовка мог переопределить определения из своего кода или из флага -D компилятора.
источник
Любой проект C находится в нескольких исходных файлах. При работе с одним исходным файлом проверки кажутся (и фактически) не имеют смысла, но при работе над большим проектом C рекомендуется проверять существующие определения перед определением константы. Идея проста: вам нужна константа в этом конкретном исходном файле, но она, возможно, уже была определена в другом.
источник
Вы можете подумать о фреймворке / библиотеке, которая дает пользователю предустановку по умолчанию, которая позволяет пользователю компилировать и работать с ней. Эти определения распространяются в разных файлах, и конечному пользователю рекомендуется включить его файл config.h, где он может настроить его значения. Если пользователь забыл некоторые определения, система может продолжать работать из-за предустановки.
источник
С помощью
#ifndef BEEPTRIM_PITCH_RATE_DEGPS #define BEEPTRIM_PITCH_RATE_DEGPS 0.2f #endif
позволяет пользователю определять значение макроса с помощью аргумента командной строки (в gcc / clang / VS)
-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f
.Есть еще одна важная причина. Переопределять макрос препроцессора иначе - ошибка. См. Этот ответ на другой вопрос SO . Без
#ifndef
проверки компилятор должен выдать ошибку, если-DBEEPTRIM_PITCH_RATE_DEGPS=0.3f
он используется в качестве аргумента командной строки при вызове компилятора.источник