Являются ли глобальные переменные злыми в Arduino?

Я относительно новичок в программировании, и многие из лучших методов кодирования, которые я читаю, показывают, что существует очень мало веских причин использовать глобальную переменную (или что лучший код вообще не имеет глобальных переменных).

Я сделал все возможное, чтобы помнить об этом, при написании программного обеспечения для создания интерфейса Arduino с SD-картой, поговорить с компьютером и запустить контроллер двигателя.

В настоящее время у меня есть 46 глобалов для примерно 1100 строк кода «начального уровня» (нет строки, содержащей более одного действия). Является ли это хорошим соотношением или я должен смотреть на его уменьшение? Также, какие практики я могу использовать для уменьшения количества глобалов?

Я спрашиваю об этом здесь, потому что я специально занимаюсь передовыми методами кодирования продуктов Arduino, а не компьютерным программированием в целом.

20 голосов | спросил ATE-ENGE 11 J000000Tuesday17 2017, 16:07:11

8 ответов


26

Они не являются злом сами по себе, но они, как правило, злоупотребляют, когда нет веских оснований для их использования.

Существует много раз, когда глобальные переменные выгодны. Тем более, что программирование Arduino под капотом значительно отличается от программирования ПК.

Самое большое преимущество глобальных переменных - это статическое распределение. Особенно с большими и сложными переменными, такими как экземпляры классов. Динамическое распределение (использование new и т. Д.) Неодобрительно из-за нехватки ресурсов.

Также вы не получаете ни одного дерева вызовов, как в обычной программе C (одна функция main(), вызывающая другие функции) - вместо этого вы фактически получаете два отдельных дерева (setup(), затем вызывающие функции loop()), что означает, что иногда глобальные переменные являются единственным способом достижения вашей цели (т. е. если вы хотите использовать ее в обоих setup() и loop()).

Нет, они не злые, и на Arduino у них все больше и больше пользы, чем на ПК.

ответил Majenko 11 J000000Tuesday17 2017, 16:19:56
16

Очень сложно дать окончательный ответ, не видя своего фактический код.

Глобальные переменные не являются злыми, и они часто имеют смысл во встроенных где вы обычно делаете большой доступ к аппаратным средствам. У тебя есть только четыре UARTS, только один порт I2C и т. д. Поэтому имеет смысл использовать глобальные переменные для переменных, привязанных к конкретным аппаратным ресурсам. И действительно, основная библиотека Arduino делает это: Serial, Serial1 и т. д. являются глобальными переменные. Кроме того, переменная, представляющая глобальное состояние программы обычно является глобальным.

  

В настоящее время у меня есть 46 глобалов для примерно 1100 строк [code]. Это   хорошее соотношение [...]

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

Тем не менее, 46 глобальных кажется мне немного большим. Если некоторые из них сохраняются постоянными значения, квалифицируйте их как const: компилятор обычно оптимизирует их хранения. Если какая-либо из этих переменных используется только в одном функцию, сделать ее локальной. Если вы хотите, чтобы его значение сохранялось между вызовами к функции, квалифицируйте ее как static. Вы также можете уменьшить количество «видимых» глобальных группировок, группируя переменные вместе внутри класс и имеющий один глобальный экземпляр этого класса. Но делайте это только тогда, когда имеет смысл собирать вещи вместе. Создание большого класса GlobalStuff ради того, чтобы иметь только одну глобальную переменную, code clearer.

ответил Edgar Bonet 11 J000000Tuesday17 2017, 16:29:32
5

Хотя я не буду использовать их при программировании для ПК, для Arduino у них есть некоторые преимущества. Большинство, если уже сказано:

  • Использование динамической памяти (создание пробелов в ограниченном пространстве кучи Arduino)
  • Доступно везде, поэтому нет необходимости передавать их в качестве аргументов (что требует пространства стека)

Кроме того, в некоторых случаях, особенно с точки зрения производительности, может быть полезно использовать глобальные переменные, а не создавать элементы при необходимости:

  • Чтобы уменьшить пробелы в области кучи
  • Динамическое выделение и /или освобождение памяти может занять значительное время
  • Переменные могут быть «повторно использованы», как список элементов глобального списка, которые используются по нескольким причинам, например. один раз в качестве буфера для SD, а затем в качестве временного буфера строк.
ответил Michel Keijzers 11 J000000Tuesday17 2017, 17:19:04
5

Основной проблемой глобальных переменных является обслуживание кода. При чтении строки кода легко найти объявление переменных, переданных как параметр или объявленных локально. Нелегко найти объявление глобальных переменных (часто это требует и IDE).

Когда у вас много глобальных переменных (40 уже много), становится трудно иметь явное имя, которое не слишком велико. Использование пространства имен - это способ выяснить роль глобальных переменных.

Плохой способ имитации пространств имен в C:

static struct {
    int motor1, motor2;
    bool sensor;
} arm;

В процессоре intel или arm доступ к глобальным переменным медленнее, чем другие переменные. Наверное, на ардуине, вероятно, наоборот.

ответил BOC 11 J000000Tuesday17 2017, 18:17:52
4

Как и во всем (кроме гете, которые действительно злы), их место занимают глобалы.

например. Если у вас есть отладочный последовательный порт или файл журнала, который вам нужен, чтобы писать везде, то часто имеет смысл сделать его глобальным. Аналогично, если у вас есть критическая информация о статусе системы, тогда ее глобальное решение часто является самым простым решением. Нет смысла иметь значение, которое вы должны передать каждой отдельной функции в программе.

Как говорили другие 46, кажется, что всего лишь для более чем 1000 строк кода, но, не зная подробностей о том, что вы делаете, трудно сказать, если вы закончили использовать их или нет.

Однако для каждого глобального вопроса задайте себе несколько важных вопросов:

Является ли имя понятным и конкретным, чтобы я случайно не использовал одно и то же имя в другом месте? Если не изменить имя.

Нужно ли это когда-либо менять? Если нет, подумайте о том, чтобы сделать его const.

Нужно ли это быть видимым повсюду или оно глобально, чтобы поддерживать значение между вызовами функций? Поэтому рассмотрим возможность локализации функции и использования ключевого слова static.

Будет ли действительно плохо испортиться, если это изменится частью кода, когда я не буду осторожен? например если у вас есть две связанные переменные, например, имя и идентификационный номер, которые являются глобальными (см. предыдущее примечание об использовании глобального, когда вам нужна информация почти везде), тогда, если один из них будет изменен без других неприятных вещей, это может случиться. Да, вы могли бы просто быть осторожными, но иногда хорошо прикладывать осторожность. например, поместите их в другой файл .c, а затем определите функции, которые устанавливают оба из них одновременно, и позволяют читать их. Затем вы включаете только функции в связанный файл заголовка, таким образом, остальная часть вашего кода может обращаться к переменным только через определенные функции и поэтому не может испортить вещи. Это, в основном, чистый способ сделать то, что разрешил бы класс c ++, но без необходимости учиться определять и создавать классы, чтобы вы не слишком много учились.

- update - Я только понял, что вы спросили о лучшей практике Arduino, а не об общем кодировании, и это скорее общий ответ на кодирование. Но, честно говоря, нет большой разницы, хорошая практика - хорошая практика. Структура startup() и loop() Arduino означает, что вам нужно использовать глобальные переменные немного больше, чем другие платформы в некоторых ситуациях, но это не сильно меняется, вы всегда в конечном итоге стремясь к лучшему, что вы можете сделать в рамках ограничений платформы, независимо от платформы.

ответил Andrew 11 J000000Tuesday17 2017, 16:49:12
3
Они злы? Может быть. Проблема с глобальными переменными заключается в том, что они могут быть доступны и изменены в любой момент времени с помощью любой функции или исполняемого кода без ограничений. Это может привести к ситуациям, которые, скажем, трудно отследить и объяснить. Поэтому желательно минимизировать количество глобалов, если возможно, вернуть количество к нулю.

Можно ли их избежать? Почти всегда да. Проблема с Arduino заключается в том, что они заставляют вас использовать этот два функциональных подхода, в которых они предполагают, что вы setup(), и вы loop(). В этом конкретном случае у вас нет доступа к объему функции вызывающего абонента из этих двух функций (возможно, main())). Если бы у вас было, вы могли бы избавиться от всех глобалов и вместо этого использовать местных жителей.

Сделайте следующее:

int main() {
  setup();

  while (true) {
    loop();
  }
  return 0;
}

Это, вероятно, более или менее то, что выглядит основная функция программы Arduino. Вместо этого переменные, необходимые как для setup(), так и для функции loop(), будут предпочтительно объявлены внутри области main() а не глобального масштаба. Затем они могли быть доступны для двух других функций посредством передачи их в качестве аргументов (при необходимости, используя указатели).

Например:

int main() {
  int myVariable = 0;
  setup(&myVariable);

  while (true) {
    loop(&myVariable);
  }
  return 0;
}

Обратите внимание, что в этом случае вам также необходимо изменить подпись обеих функций.

Поскольку это может оказаться невозможным и нежелательным, я вижу действительно единственный способ удалить большинство глобальных программ из программы Arduino без изменения структуры принудительной структуры.

Если я правильно помню, вы отлично можете использовать C ++ во время программирования для Arduino, а не C. Если вы еще не знакомы с ООП (объектно-ориентированное программирование) или C ++, может потребоваться некоторое привыкание и некоторые чтения.

Мое предложение состояло в том, чтобы создать класс программы и создать один глобальный экземпляр этого класса. Класс должен считаться планом для объектов.

Рассмотрим следующую примерную программу:

class Program {
public:      
  Program();

  void setup();
  void loop();

private:
  int myFirstSampleVariable;
  int mySecondSampleVariable;
};

Program::Program() :
  myFirstSampleVariable(0),
  mySecondSampleVariable(0)
{

}

void Program::setup() {
  // your setup code goes here
}

void Program::loop() {
  // your loop code goes here
}

Program program; // your single global

void setup() {
  program.setup();
}

void loop() {
  program.loop();
}

VoilÃ, мы избавились от почти всех глобалов. Функции, в которых вы начнете добавлять логику приложения, будут Program::setup() и Program::loop(). Эти функции имеют доступ к конкретным переменным-членам-экземплярам myFirstSampleVariable и mySecondSampleVariable, тогда как традиционный setup() и loop() функции не имеют доступа, поскольку эти переменные отмечены как частные. Эта концепция называется инкапсуляция данных или скрытие данных.

Преподавание вас ООП и /или C ++ немного выходит за рамки ответа на этот вопрос, поэтому я остановлюсь здесь.

Подводя итог: следует избегать глобализации, и почти всегда можно резко уменьшить количество глобалов. Также, когда вы программируете для Arduino.

Самое главное, я надеюсь, что мой ответ несколько полезен для вас:)

ответил Arjen 12 J000000Wednesday17 2017, 16:14:42
2

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

Что такое глобальная переменная, является неотъемлемым предположением, что есть только одна вещь (неважно, говорим ли мы о глобальном массиве или карте, которая может содержать несколько вещей, которая все еще содержит предположение, что существует только один такой список или отображение, а не несколько независимых).

Итак, прежде чем вы будете использовать глобальное, вы хотите спросить себя: возможно ли, что я когда-нибудь захочу использовать более чем одну из этих вещей? Если он окажется правдивым по линии, вам придется изменить код, чтобы не глобализовать эту вещь, и вы, вероятно, узнаете, что другие части вашего кода зависят от этого предположения об уникальности, поэтому вы также придется исправлять их, и процесс становится утомительным и подверженным ошибкам. «Не использовать глобалы» учат, потому что обычно это довольно небольшая стоимость, чтобы избежать глобалов с самого начала, и это позволяет избежать возможности заплатить большую стоимость позже.

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

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

Итак, продолжайте использовать глобальные переменные, когда они кажутся стоящими. Кодекс полиции не придет и не получит вас. Просто знайте, что неправильный выбор может привести к гораздо большему труду для вас в будущем, поэтому, если вы не уверены ...

ответил hobbs 13 J000000Thursday17 2017, 10:25:09
0
  

Являются ли глобальные переменные злом в Arduino?

ничто изначально не является злом, включая глобальные переменные. Я бы охарактеризовал его как «необходимое зло» - он может сделать вашу жизнь намного легче, но к ней следует подходить с осторожностью.

  

Кроме того, какие практики я могу использовать для уменьшения числа глобалов?

использовать функции-обертки для доступа к вашим глобальным переменным. поэтому вы, по крайней мере, управляете им с точки зрения сферы.

ответил dannyf 13 J000000Thursday17 2017, 12:57:28

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

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

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