#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.

Полезные материалы