#define
#define — директива препроцессора, которая подставляет имя вместо значения прямо в код до компиляции, не занимая памяти; для типизированных констант лучше использовать const.
Полная статья
Описание
#define — директива препроцессора C++, которая связывает имя с некоторым значением ещё до начала компиляции. Когда компилятор встречает это имя в коде, он буквально подставляет вместо него указанное значение. Поскольку подстановка происходит на этапе препроцессинга, такие константы не занимают места ни в оперативной, ни в программной памяти микроконтроллера.
Это удобно, когда нужно дать осмысленное имя числу или строке, которые используются в нескольких местах скетча — например, номеру пина, пороговому значению датчика или размеру буфера.
Однако у #define есть подводные камни. Препроцессор делает текстовую замену без какого-либо понимания типов и контекста. Если имя макроса случайно совпадёт с частью другого идентификатора, компилятор подставит значение туда, куда вы не ожидали, и вы получите трудночитаемые ошибки.
По этой причине в Arduino-коде предпочтительнее использовать const для объявления именованных констант — он типобезопасен и ведёт себя предсказуемо. #define стоит оставить для случаев, когда const не подходит по каким-либо причинам.
Синтаксис
#define constantName value
Параметры
constantName: имя макроса — по соглашению пишется заглавными буквами, чтобы визуально отличаться от переменныхvalue: значение, которое препроцессор будет подставлять вместо имени макроса
Пример кода
#define ledPin 3
// Компилятор заменит любое упоминание ledPin значением 3 во время компиляции.
Примечания и предупреждения
После строки #define не ставится точка с запятой. Если добавить её, препроцессор включит символ ; в подставляемое значение, и компилятор выдаст непонятную ошибку уже в том месте кода, где используется макрос — не в строке с #define.
#define ledPin 3; // это ошибка
Аналогично, не используйте знак = между именем макроса и его значением. Строка вида #define PIN = 13 приведёт к такой же загадочной ошибке компилятора в месте использования.
#define ledPin = 3 // это тоже ошибка
Где применяется
- Задать номер пина один раз в начале скетча, чтобы потом менять его в одном месте.
- Определить константы протокола или размеры массивов, которые не должны меняться во время выполнения.
- Условная компиляция:
#define DEBUGв паре с#ifdef DEBUGпозволяет включать и выключать отладочный вывод без удаления кода. - Совместимость с библиотеками, которые ожидают макросы препроцессора, а не переменные.
Практические замечания
- Если вам нужна просто именованная константа с конкретным типом, используйте
const— это безопаснее и понятнее. - Имена макросов принято писать
ЗАГЛАВНЫМИ_БУКВАМИ, чтобы сразу было видно, что это не переменная. #defineне создаёт переменную: нельзя взять адрес макроса через&или передать его по ссылке.- Если макрос содержит выражение, а не одно число, оборачивайте его в скобки:
#define DOUBLE(x) ((x) * 2)— иначе порядок операций может дать неожиданный результат. - При странных ошибках компилятора в строках, где используется имя макроса, первым делом проверьте, нет ли лишней точки с запятой или знака
=в строке с#define.