Общие сведения о встроенном C:что такое структуры?
После представления структур мы рассмотрим некоторые важные приложения этого мощного объекта данных. Затем мы исследуем синтаксис языка C, чтобы объявить структуру. Наконец, мы кратко представим требования к выравниванию данных. Мы увидим, что можем уменьшить размер структуры, просто изменив порядок ее членов.
В этой статье представлена основная информация о структурах во встроенном программировании на C.
После введения структур мы рассмотрим некоторые важные приложения этого мощного объекта данных. Затем мы исследуем синтаксис языка C, чтобы объявить структуру. Наконец, мы кратко представим требования к выравниванию данных. Мы увидим, что можем уменьшить размер структуры, просто изменив порядок ее членов.
Структуры
Несколько переменных одного типа, которые логически связаны друг с другом, могут быть сгруппированы в массив. Работа с группой, а не с набором независимых переменных, позволяет нам упорядочивать данные и использовать их более удобно. Например, мы можем определить следующий массив для хранения последних 50 выборок АЦП, который оцифровывает голосовой ввод:
uint16_t voice [50];
Обратите внимание, что uint16_t представляет собой целочисленный тип без знака с шириной ровно 16 бит. Это определено в стандартной библиотеке C stdint.h , который предоставляет типы данных определенной длины в битах независимо от системных спецификаций.
Массивы можно использовать для группировки ряда переменных с одним и тем же типом данных. Что делать, если существует связь между разными переменными типы данных? Можем ли мы рассматривать эти переменные как группу в нашей программе? Например, предположим, что нам нужно указать частоту дискретизации АЦП, который генерирует голос . массив выше. Мы можем определить переменную с плавающей запятой для хранения частоты дискретизации:
float sample_rate;
Хотя переменные voice и sample_rate связаны друг с другом, они определяются как две независимые переменные. Чтобы связать эти две переменные друг с другом, мы можем использовать мощную конструкцию данных языка C, называемую структурой. Структуры позволяют нам группировать различные типы данных и работать с ними как с единым объектом данных. Структура может включать в себя различные типы переменных, такие как другие структуры, указатели на функции, указатели на структуры и т. Д. В голосовом примере мы можем использовать следующую структуру:
struct record {uint16_t voice [50]; float sample_rate;};
В данном случае у нас есть структура под названием запись который имеет два разных члена или поля:первый член - это массив uint16_t elements, а второй член - это переменная типа float. Синтаксис начинается с ключевого слова struct . . Слово после ключевого слова struct является необязательным именем, используемым для ссылки на структуру позже. Мы обсудим другие детали определения и использования структур в оставшейся части статьи.
Почему структуры важны?
Приведенный выше пример указывает на важное применение структур, то есть определение зависящих от приложения объектов данных, которые могут связывать отдельные переменные разных типов друг с другом. Это не только приводит к эффективному способу манипулирования данными, но также позволяет нам реализовывать специализированные структуры, называемые структурами данных.
Структуры данных могут использоваться для различных приложений, таких как обмен сообщениями между двумя встроенными системами и хранение данных, собранных с датчика, в несмежных ячейках памяти.
Рисунок 1. Структуры можно использовать для реализации связного списка.
Кроме того, структуры являются полезными объектами данных, когда программе требуется доступ к регистрам периферийного устройства микроконтроллера с отображением памяти. В следующей статье мы рассмотрим структурные приложения.
Рисунок 2. Карта памяти микроконтроллера STM32. Изображение любезно предоставлено Embedded Systems with ARM.
Объявление структуры
Чтобы использовать структуры, нам сначала нужно указать шаблон структуры. Рассмотрим пример кода ниже:
struct record {uint16_t voice [4]; float sample_rate;};
Это определяет макет или шаблон для создания будущих переменных этого типа. Этот шаблон включает в себя массив uint16_t и переменная типа float. Имя шаблона - запись . , и это идет после ключевого слова struct . Стоит отметить, что для хранения шаблона структуры не выделяется память. Выделение памяти происходит только после того, как определена структурная переменная на основе этого макета. Следующий код объявляет переменную mic1 шаблона выше:
struct record mic1;
Теперь для переменной mic1 выделен раздел памяти. . В нем есть место для хранения четырех uint16_t элементы массива и одну переменную с плавающей запятой.
Доступ к членам структуры можно получить с помощью оператора члена (.). Например, следующий код присваивает 100 первому элементу массива и копирует значение sample_rate . в fs переменная (должна иметь тип float).
mic1.voice [0] =100; fs =mic1.sample_rate;
Другие способы объявления структуры
Мы рассмотрели один из способов объявления структур в предыдущем разделе. Язык C поддерживает некоторые другие форматы, которые будут рассмотрены в этом разделе. Вы, вероятно, будете придерживаться одного формата в своих программах, но знание других иногда может быть полезно.
Общий синтаксис объявления шаблона структуры:
struct tag_name {type_1 member_1; type_2 member_2; … Type_n member_n;} имя_переменной;
tag_name и имя_переменной необязательные идентификаторы. Обычно мы видим хотя бы один из этих двух идентификаторов, но в некоторых случаях мы можем удалить их оба.
Синтаксис 1: Когда оба tag_name и имя_переменной присутствуют, мы определяем структурную переменную сразу после шаблона. Используя этот синтаксис, мы можем переписать предыдущий пример следующим образом:
struct record {uint16_t voice [4]; float sample_rate;} mic1;
Теперь, если нам нужно определить другую переменную ( mic2 ), мы можем написать
struct record mic2;
Синтаксис 2: Только имя_переменной Включено. Используя этот синтаксис, мы можем переписать пример из предыдущего раздела следующим образом:
struct {uint16_t voice [4]; float sample_rate;} mic1;
В этом случае мы должны определить все наши переменные сразу после шаблона, и мы не можем определить какие-либо другие переменные позже в нашей программе (потому что шаблон не имеет имени, и мы не можем ссылаться на него позже).
Синтаксис 3: В этом случае нет tag_name или имя_переменной . Шаблоны структур, определенные таким образом, называются анонимными структурами. Анонимная структура может быть определена внутри другой структуры или объединения. Пример приведен ниже:
struct test {// Анонимная структура struct {float f; char a; };} test_var;
Чтобы получить доступ к членам вышеуказанной анонимной структуры, мы можем использовать оператор-член (.). Следующий код присваивает 1,2 члену f . .
test_var.f =1.2;
Поскольку структура анонимна, мы получаем доступ к ее членам, используя оператор члена только один раз. Если бы у него было имя, как в следующем примере, нам пришлось бы использовать оператор-член дважды:
struct test {struct {float f; char a; } вложенный;} test_var;
В этом случае мы должны использовать следующий код, чтобы присвоить 1,2 параметру f :
test_var.nested.f =1.2;
Как видите, анонимные структуры могут сделать код более читабельным и менее подробным. Также можно использовать ключевое слово typedef вместе со структурой для определения нового типа данных. Мы рассмотрим этот метод в следующей статье.
Схема памяти для структуры
Стандарт C гарантирует, что элементы структуры будут располагаться в памяти один за другим в том порядке, в котором они объявлены внутри структуры. Адрес памяти первого члена будет таким же, как адрес самой структуры. Рассмотрим следующий пример:
struct Test2 {uint8_t c; uint32_t d; uint8_t e; uint16_t f;} MyStruct;
Для хранения переменных c, d, e и f будут выделены четыре ячейки памяти. Порядок ячеек памяти будет соответствовать порядку объявления членов:у ячейки c будет наименьший адрес, затем появятся d, e и, наконец, f. Сколько байтов нам нужно для хранения этой структуры? Учитывая размер переменных, мы знаем, что для хранения этой структуры требуется как минимум 1 + 4 + 1 + 2 =8 байтов. Однако, если мы скомпилируем этот код для 32-разрядной машины, мы неожиданно заметим, что размер MyStruct составляет 12 байт, а не 8! Это связано с тем, что компилятор имеет определенные ограничения при выделении памяти для разных членов структуры. Например, 32-битное целое число может храниться только в тех ячейках памяти, адрес которых делится на четыре. Такие ограничения, называемые требованиями к выравниванию данных, реализованы, чтобы позволить процессору более эффективно обращаться к переменным. Выравнивание данных приводит к потере некоторого пространства (или заполнения) в структуре памяти. Эта тема только вводится здесь; мы рассмотрим подробности в следующей статье этой серии.
Рисунок 3. Выравнивание данных приводит к потере некоторого пространства (или заполнения) в макете памяти.
Зная о требованиях к выравниванию данных, мы можем изменить порядок членов в структуре и сделать использование памяти более эффективным. Например, если мы перепишем приведенную выше структуру, как показано ниже, ее размер уменьшится до 8 байтов на 32-битной машине.
struct Test2 {uint32_t d; uint16_t f; uint8_t c; uint8_t e;} MyStruct;
Для встроенной системы с ограничением памяти можно значительно сэкономить, если уменьшить размер объекта данных с 12 до 8 байтов, особенно когда программе требуется много таких объектов данных.
В следующей статье мы обсудим выравнивание данных более подробно и рассмотрим некоторые примеры использования структур во встроенных системах.
Резюме
- Структуры позволяют нам определять зависящие от приложения объекты данных, которые могут связывать друг с другом отдельные переменные разных типов. Это приводит к эффективным средствам манипулирования данными.
- Специализированные структуры, называемые структурами данных, могут использоваться для различных приложений, таких как обмен сообщениями между двумя встроенными системами и хранение данных, собранных с датчика, в несмежных ячейках памяти.
- Структуры полезны, когда нам нужно получить доступ к регистрам периферийного устройства микроконтроллера с отображением памяти.
- Возможно, мы сможем повысить эффективность использования памяти, изменив порядок членов в структуре.
Чтобы увидеть полный список моих статей, посетите эту страницу.
Встроенный