РЕДАКТИРОВАТЬ: microtherion дает превосходный ответ, который исправляет некоторые из моих пунктов здесь, особенно об использовании памяти.
Как вы определили, в определенных ситуациях вы вынуждены использовать a #define
, потому что компилятор не допустит const
переменную. Точно так же в некоторых ситуациях вы вынуждены использовать переменные, например, когда вам нужен массив значений (т.е. вы не можете иметь массив #define
).
Тем не менее, существует много других ситуаций, в которых не существует единственного «правильного» ответа. Вот несколько рекомендаций, которым я бы следовал:
Безопасность типов
С общей точки зрения программирования const
переменные обычно предпочтительнее (где это возможно). Основной причиной этого является безопасность типов.
#define
(Препроцессор макро) непосредственно копирует буквенное значение в каждое место в коде, что делает каждый независимо использование. Это может гипотетически привести к неоднозначности, потому что тип может быть решен по-разному в зависимости от того, как / где он используется.
const
Переменная только когда - либо один тип, который определяется его декларации, и решены в ходе инициализации. Он часто требует явного приведения, прежде чем он будет вести себя по-другому (хотя существуют различные ситуации, когда его можно безопасно неявно повышать по типу). По крайней мере, компилятор может (если он настроен правильно) выдавать более надежное предупреждение при возникновении проблемы с типом.
Возможным обходным путем для этого является включение явного приведения или суффикса типа в #define
. Например:
#define THE_ANSWER (int8_t)42
#define NOT_QUITE_PI 3.14f
Такой подход может потенциально вызвать проблемы синтаксиса в некоторых случаях, в зависимости от того, как он используется.
Использование памяти
В отличие от вычислений общего назначения, память имеет преимущество при работе с чем-то вроде Arduino. Использование const
переменной против a #define
может повлиять на то, где данные хранятся в памяти, что может заставить вас использовать одну или другую.
const
переменные (как правило) будут храниться в SRAM вместе со всеми другими переменными.
- Используемые литеральные значения
#define
часто хранятся в программном пространстве (флэш-память) вместе с самим эскизом.
(Обратите внимание, что есть разные вещи, которые могут повлиять на то, как и где что-то хранится, например, конфигурация компилятора и оптимизация.)
SRAM и Flash имеют разные ограничения (например, 2 КБ и 32 КБ соответственно для Uno). Для некоторых приложений достаточно просто запустить SRAM, поэтому полезно перенести некоторые вещи во Flash. Обратное также возможно, хотя, вероятно, менее распространено.
PROGMEM
Можно получить преимущества безопасности типов и одновременно хранить данные в программном пространстве (Flash). Это делается с помощью PROGMEM
ключевого слова. Он не работает для всех типов, но обычно используется для массивов целых чисел или строк.
Общая форма, приведенная в документации, выглядит следующим образом:
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};
Строковые таблицы немного сложнее, но в документации есть полная информация.