В чем разница между объявлением переменной вне цикла и объявлением статического внутреннего цикла?

Это два способа, которыми я могу держать переменную вне цикла (или любой функции).

Во-первых, я могу объявить его с глобальной областью вне цикла:

void setup()
{
    Serial.begin(9600);
}

int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    delay(250);
}

Я также могу объявить его статическим внутри цикла:

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    static int count = 0;

    Serial.println(count);
    count++;

    delay(250);
}

Какая разница, если таковая вообще возникнет?

9 голосов | спросил Cybergibbons 1 MarpmSat, 01 Mar 2014 14:00:28 +04002014-03-01T14:00:28+04:0002 2014, 14:00:28

4 ответа


10

Самое основное отличие от области видимости.

В первом случае вы объявляете глобальную переменную. Это переменная, доступная во всех областях после определения.

void setup()
{
    Serial.begin(9600);
}

void inc();
int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

void inc() //Can edit the value of count
{
  count=count+1;
};

Во втором случае вы объявляете статическую переменную с локальной областью. Переменная будет сохраняться для всего запуска программы, аналогичной глобальным переменным, но будет доступна только в кодовом блоке, в котором она объявлена. Это тот же пример с одним изменением. count теперь объявляется как статическая переменная внутри цикла loop.

void inc();

void loop()
{
    static int count = 0;
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

Это не будет компилироваться, поскольку функция inc() не имеет доступа к count.

Глобальные переменные, какими бы полезными они ни были, приходят с некоторыми подводными камнями. Это может даже нанести ущерб, когда дело доходит до написания программ, которые могут взаимодействовать с физическим окружением. Это очень простой пример того, что, скорее всего, произойдет, как только программы начнут увеличиваться. Функция может непреднамеренно изменять состояние глобальной переменной.

void setup()
{
    Serial.begin(9600);
}
void another_function();
int state=0;

void loop()
{
    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Inadvertently changes state
  state=1;

}

Такие случаи очень сложно отлаживать. Этот тип , однако, может быть легко обнаружен, просто используя статическую переменную.

void setup()
{
    Serial.begin(9600);
}
void another_function();

void loop()
{
    static int state=0;

    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Results in a compile time error. Saves time.
  state=1;

}
ответил asheeshr 1 MarpmSat, 01 Mar 2014 14:45:19 +04002014-03-01T14:45:19+04:0002 2014, 14:45:19
5

С точки зрения функциональности обе версии генерируют одинаковый результат, поскольку в обоих случаях значение count сохраняется между выполнением цикла loop() (либо потому, что это глобальная переменная или потому, что она помечена как static и поэтому сохраняет ее значение).

Итак, решение, которое выбрать, сводится к следующим аргументам:

  1. Как правило, в информатике рекомендуется сохранять ваши переменные как можно более локальными с точки зрения области . Это обычно приводит к значительно более четкому коду с меньшими побочными эффектами и снижает вероятность того, что кто-то другой использует эту глобальную переменную, закручивая вашу логику). Например. в вашем первом примере другие области логики могут изменить значение count, тогда как во втором это может сделать только эта конкретная функция loop()).
  2. Глобальные и статические переменные всегда занимают память , где, как местные жители, только когда они находятся в области видимости. В приведенных выше примерах нет никакой разницы (поскольку в одном вы используете глобальную, в другой - статическую переменную), но в более крупных и более сложных программах это может и вы могли бы сэкономить память, используя нестатические локали. Тем не менее : если у вас есть переменная в логической области, которая выполняется очень часто, подумайте о том, чтобы сделать ее статичной или глобальной, поскольку в противном случае вы теряете крошечный бит производительности каждый раз, когда логика область вводится, поскольку для выделения памяти требуется немного времени для этого нового экземпляра переменной. Вам нужно найти баланс между нагрузкой на память и производительностью.
  3. Другие элементы, такие как лучший макет для статического анализа или оптимизации компилятором, также могут вступить в игру.
  4. В некоторых особых сценариях могут возникнуть проблемы с непредсказуемым порядком инициализации статических элементов (не уверен в этой точке, сравните это ссылка , хотя).

Источник: Аналогичная тема на arduino .cc

ответил Philip Allgaier 1 MarpmSat, 01 Mar 2014 14:49:55 +04002014-03-01T14:49:55+04:0002 2014, 14:49:55
2

Обе переменные являются статическими - они сохраняются для всего сеанса выполнения. Глобальная видимость для любой функции, если она объявляет - не определяет - глобальную, или если функция следует определению в том же модуле компиляции (файл + включает).

Перемещение определения count внутрь функции ограничивает область видимости до ближайшего охватывающего набора {} es и дает ему время жизни вызова функции ( он создается и уничтожается при вводе и выходе функции). Объявив его static, он также дает ему время жизни сеанса выполнения, которое существует от начала до конца сеанса выполнения, сохраняющегося при вызове функций.

BTW: будьте осторожны при использовании инициализированной статики внутри функции, поскольку я видел, что некоторые версии компилятора gnu ошибочны. Автоматическая переменная с инициализатором должна быть создана и инициализирована для каждой записи функции. Статичность с инициализатором должна быть инициализирована только один раз, во время установки выполнения, перед тем как main () получит управление (как глобальное). У меня была локальная статика, которая была повторно инициализирована для каждой записи функции, как если бы они были автоматикой, что неверно. Проверьте свой собственный компилятор.

ответил JRobert 3 MaramMon, 03 Mar 2014 02:11:52 +04002014-03-03T02:11:52+04:0002 2014, 02:11:52
-3

В соответствии с документацией Atmel: «Если объявлена ​​глобальная переменная, уникальный адрес в SRAM будет назначен этой переменной в момент времени программы».

Полная документация здесь (Совет № 2 для глобальных переменных): http: //www. atmel.com/images/doc8453.pdf

ответил Void Main 1 MarpmSat, 01 Mar 2014 14:41:45 +04002014-03-01T14:41:45+04:0002 2014, 14:41:45

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132