Структуры и перечисления
Структуры
Структура struct
- очень интересный тип данных: это набор переменных разного типа, объединённых одним именем. В некоторых случаях структуры позволяют сильно упростить написание кода и сделать его более понятным, а также упростить придумывание новых имён для переменных. А ещё структура - это практически класс (урок про классы)! Но без механизмов наследования и приватных-публичных членов.
Структура объявляется по следующей схеме:
struct ярлык { тип_данных имя_переменной_1; тип_данных имя_переменной_2; тип_данных имя_переменной_3; };
Ярлык будет являться новым типом данных. Используя этот ярлык, можно объявлять уже непосредственно саму структуру как переменную:
ярлык имя_структуры; // объявить одну структуру ярлык имя_структуры_1, имя_структуры_2; // объявить две структуры ярлык имя_структуры[5]; // объявить массив структур
Также есть вариант объявления структуры без ярлыка, т.е. создаём структуру и сразу указываем её имя в конце.
struct { тип_данных имя_переменной_1; тип_данных имя_переменной_2; тип_данных имя_переменной_3; } имя_структуры;
- Обращение к члену структуры производится через точку:
имя_структуры.имя_переменной
и позволяет менять или читать значение. - Если две структуры объявлены одним ярлыком, то можно одну структуру просто приравнять к другой, все переменные запишутся соответственно на свои места.
- Также можно изменить все значения переменных в структуре вот таким образом:
имя_структуры = (ярлык) {значение_переменной_1, значение_переменной_2, значение_переменной_3};
- Объявить структуру с указанием значений переменных можно так:
ярлык имя_структуры{значение_переменной_1, значение_переменной_2, значение_переменной_3};
Рассмотрим большой пример:
struct myStruct { // создаём ярлык myStruct boolean a; byte b; int c; long d; byte arr[5]; }; myStruct kek; // создаём структуру kek // создаём массив структур cheburek типа myStruct myStruct cheburek[3]; void setup() { // присвоим членам структуры значения вручную kek.a = true; kek.b = 10; kek.c = 1200; kek.d = 789456; kek.arr[0] = 10; kek.arr[1] = 20; kek.arr[2] = 30; // присвоим структуру kek структуре cheburek номер 0 cheburek[0] = kek; // присвоим элемент массива из структуры kek // структуре cheburek номер 1 cheburek[0].arr[1] = kek.arr[1]; // заполним данными структуру cheburek номер 2 cheburek[2] = (myStruct) { false, 30, 3200, 321654, {1, 2, 3, 4, 5} }; }
Для чего нужны структуры? В большинстве примеров в интернете приводится использование структур для создания базы данных: имя, фамилия, номер телефона, адрес и т.д. Структуры очень удобно передавать по радио и другим интерфейсам связи, на моей практике - в структуре удобнее всего хранить настройки, потому что её можно целиком записать в EEPROM одной строчкой и одной строчкой оттуда же её прочитать, не заморачиваясь с адресами.
Вложенные структуры
Структуры также могут быть вложены друг в друга, доступ к нужному элементу осуществляется так же при помощи оператора "точка", вот простой пример:
struct Values { int value1; float value2; }; struct BigStruct { Values values; // элемент типа Values int otherValue; }; BigStruct myStruct; myStruct.values.value2 = 3.14;
Перечисления
Перечисления (enum
- enumeration) - тип данных, представляющий собой набор именованных констант, нужен для удобства написания программы. Допустим у нас есть переменная mode, отвечающая за номер режима работы устройства. Мы для себя запоминаем, какому значению переменной какой режим будет соответствовать, и где-нибудь себе записываем, например 0 - обычный режим, 1 - режим ожидания, 2 - режим настройки_1, 3 - режим настройки_2, 4 - калибровка, 5 - аварийный режим, ошибка. При написании или чтении программы часто придётся обращаться к этому списку, чтобы не запутаться. Можно сделать первый шаг по оптимизации: обозвать каждый режим при помощи константы (дефайна):
#define NORMAL 0 #define WAITING 1 #define SETTINGS_1 2 #define SETTINGS_2 3 #define CALIBRATION 4 #define ERROR_MODE 5
Таким образом вместо цифры можно будет использовать понятные слова и ориентироваться в коде будет гораздо проще. Но возникает проблема уникальности имён дефайнов.
Использование enum
ещё немного упрощает эту задачу: перечисление позволяет создать переменную (по умолчанию имеет тип int
), которая может принимать только те "названия", которые для неё указаны. Это удобно также тем, что компилятор выдаст ошибку при создании перечислений с одинаковыми значениями. В случае с дефайнами программа просто будет работать неправильно! Объявление перечисления чем-то похоже на объявление структуры:
enum ярлык {имя1, имя2, имя3, имя4, имя5};
Таким образом мы объявили ярлык. Теперь, используя этот ярлык, можно объявить само перечисление:
ярлык имя_перечисления;
Также как и у структур, можно объявить перечисление без создания ярлыка (зачем нам лишняя строчка?):
enum {имя1, имя2, имя3, имя4, имя5} имя_перечисления;
Созданное таким образом перечисление является переменной, которая может принимать указанные для неё имена, также с этими именами её можно сравнивать. Теперь самое главное: имена для программы являются числами, начиная с 0 и далее по порядку увеличиваясь на 1. В абстрактном примере выше имя1 равно 0, имя2 равно 1, имя3 равно 2, и так далее. Помимо указанных имён, перечислению можно приравнивать числа напрямую, а также сравнивать с числами. Рассмотрим пример:
// создаём перечисление modes // не создавая ярлык enum { NORMAL, WAITING, SETTINGS_1, SETTINGS_2, CALIBRATION, ERROR_MODE, } modes; void setup() { Serial.begin(9600); // для отладки modes = CALIBRATION; // присваивание значения // можем сравнивать if (modes == CALIBRATION) { Serial.println("calibr"); } else if (modes == ERROR_MODE) { Serial.println("error"); } // присваиваем числом modes = 3; // по нашему порядку это будет SETTINGS_2 }
Порядок автоматической нумерации можно изменить, задав начальное значение. От него всё будет и дальше изменяться на единицу:
enum {SET1 = 1, SET2, SET3, SET4, SET5} settings;
Таким образом SET1
имеет значение 1, SET2
будет 2 и так далее по порядку.
Полезные страницы
- Набор GyverKIT – большой стартовый набор Arduino моей разработки, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
- Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
- Полная документация по языку Ардуино, все встроенные функции и макросы, все доступные типы данных
- Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
- Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
- Поддержать автора за работу над уроками
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])