Arduino

технологии

Что использовать: статические или глобальные переменные

Давайте разберем тонкости использования глобальных и статических переменных в скетчах.

Начнем с примера. Рассмотрим простую задачу: нам нужно отправлять значение температуры с датчика. И, что важно, отправлять нужно только новое значение, если оно изменилось. Такой подход имеет преимущества: экономия трафика, упрощение логики на принимающей стороне. Скетч будет выглядеть примерно так:

#include <Arduino.h>
...
int lastTemperature = 0;
...
void setup()
{
  ...
}

void loop()
{
    int newTemperature = sensor.getTemperature();
    if (newTemperature != lastTemperature) {
        client.sendNewTemperature(newTemperature);
        lastTemperature = newTemperature;
    }
}

Все предельно ясно: сохраняем последнее значение температуры. Получаем новое значение, сравниваем с сохраненным и если оно изменилось, отправляем новое значение и сохраняем его. Для сохранения последнего значения температуры используем глобальную переменную lastTemperature.

Рассмотрим второй вариант реализации:

#include <Arduino.h>
...
void setup()
{
  ...
}

void loop()
{
    static int lastTemperature = 0;
    int newTemperature = sensor.getTemperature();
    if (newTemperature != lastTemperature) {
        client.sendNewTemperature(newTemperature);
        lastTemperature = newTemperature;
    }
}

Разница в том, что для хранения последнего значения температуры мы используем статическую переменную. Что же такое статические переменные и чем они отличаются от обычных локальных переменных? Давайте обратимся к документации:

Ключевое слово static используется для создания переменных с областью видимости только в текущей функции. Однако, в отличии от локальных переменных, которые создаются и уничтожаются при каждом вызове функции, статические переменные остаются за пределами вызова функции, сохраняя свои значения между вызовами функции.
Переменные, объявленные как статические, будут создаваться и инициализироваться только при первом вызове функции.

Итак, судя по документации, код будет работать абсолютно корректно и, на первый взгляд, никакой разницы нет, использовать глобальную переменную или статическую. Но на самом деле, используя статическую переменную, мы получаем следующий преимущества:

  • Локальная область видимости позволит избежать ошибок
  • Улучшится читаемость и поддерживаемость кода
  • В некоторых случаях код будет работать быстрее
Рассмотрим подробнее каждый пункт.

Локальная область видимости

Обратите внимание на первый пример, в котором мы использовали глобальную переменную. Изменить ее значение можно из любой функции скетча. В приведенном примере менее 20 строчек кода и в нем трудно ошибиться, на деле же скетч будет сильно больше и есть много шансов допустить ошибку, перетерев значение глобальной переменной. Локальная же область видимости, во-первых, гарантирует, что значение переменной будет изменено только в текущей функции, а, во-вторых, позволит вынести этот функционал в отдельный класс или библиотеку, и переменная вообще не будет нам мешать.

Чище код

Когда мы читаем чужой или свой же код, написанный насколько лет назад, мы не помним всех его тонкостей. В коде могут полностью отсутствовать комментарии, а имена переменных могут быть не достаточно "говорящими", чтобы сразу понять, для чего эта переменная используется. И если мы видим, что переменная статическая, мы сразу будем знать, что ее значение не меняется нигде, кроме текущей функции. А также мы будем понимать, что ее не просто так объявили статической и она сохраняет какое-то значение между вызовами функции.

Код будет работать быстрее

Доступ к памяти со значением глобальной и локальной переменной, конечно, происходит с одинаковой скоростью. Однако компилятор, видя статическую переменную, понимает, что она принадлежит текущей функции, и может произвести некоторую оптимизацию. Например, может хранить переменную в регистре вызова функции. Не будем вдаваться в подробности, главное, что программа будет работать в некоторых случаях быстрее, и это уже неплохо. А с учетом остальных преимуществ, чаще используйте статические переменные, а не глобальные.