Структуры в встроенном C: практическое руководство по определению, использованию и оптимизации памяти
Структуры — краеугольный камень эффективного встроенного программирования на C. В этой статье мы рассмотрим их практические применения, синтаксис объявления и влияние выравнивания данных на использование памяти. Грамотная упорядочивание членов структуры часто позволяет сократить размер объектов данных, что критично в ресурсоограниченных средах.
Статья дает лаконичный, но исчерпывающий обзор структур во встроенном C. Мы покроем их реальные применения, правильное объявление и тонкие правила выравнивания данных, влияющие на размер структур.
Структуры
Когда несколько переменных одного типа связаны логически, удобен массив. Например, для хранения последних 50 отсчетов АЦП, оцифровывающего голосовой вход, можно использовать:
uint16_t voice[50];
Здесь uint16_t — беззнаковое 16-битное целое, определенное в stdint.h, гарантирующее одинаковый размер на всех платформах.
Но что, если нужно сгруппировать переменные разных типов — скажем, массив отсчетов и частоту дискретизации АЦП? Объявление их как отдельных независимых переменных создает лишние накладные расходы. Вместо этого можно инкапсулировать их в структуру:
struct record { uint16_t voice[50]; float sample_rate; };
Структура record теперь содержит и массив uint16_t, и float в едином логически связанном объекте данных.
Почему структуры важны?
Структуры позволяют ассоциировать разнородные переменные в сплошную единицу, упрощая манипуляции и повышая читаемость. Они лежат в основе более сложных структур данных — связных списков и буферов сообщений, повсеместно используемых во встроенных коммуникациях и обработке сенсорных данных.
Например, память-отображаемые периферийные устройства микроконтроллеров часто представлены структурами, зеркалящими раскладку аппаратных регистров, что дает прямой доступ к регистрам через синтаксис членов.

Рисунок 1. Структуры могут использоваться для реализации связного списка.

Рисунок 2. Карта памяти STM32 MCU. Изображение предоставлено Embedded Systems with ARM.
Объявление структуры
Сначала определяете шаблон структуры. Пример:
struct record { uint16_t voice[4]; float sample_rate; };
Сам шаблон не потребляет память; выделение происходит только при объявлении переменной этого типа:
struct record mic1;
Теперь mic1 занимает место для четырех элементов uint16_t и одного float. Доступ к членам через точечный оператор:
mic1.voice[0] = 100; float fs = mic1.sample_rate;
Другие способы объявления структуры
Хотя самый частый паттерн — сначала определить структуру, потом объявить переменные, C предлагает альтернативные синтаксисы:
Синтаксис 1: тег и переменная вместе
struct record { uint16_t voice[4]; float sample_rate; } mic1;
Последующие переменные можно объявлять отдельно:
struct record mic2;
Синтаксис 2: анонимный шаблон
struct { uint16_t voice[4]; float sample_rate; } mic1;
Здесь шаблон нельзя переиспользовать, так как у него нет имени.
Синтаксис 3: анонимная вложенная структура
struct test { struct { float f; char a; }; } test_var;
Доступ к внутренним членам напрямую:
test_var.f = 1.2f;
Анонимные структуры уменьшают вербальность, но используйте их с осторожностью для ясности.
Расположение в памяти для структуры
Стандарт C гарантирует, что члены расположены в памяти последовательно, в порядке объявления. Например:
struct Test2 { uint8_t c; uint32_t d; uint8_t e; uint16_t f; } MyStruct;
На 32-битной машине sizeof(MyStruct) = 12 байт из-за выравнивания, которое выравнивает uint32_t по 4-байтовой границе. Переупорядочивание членов может устранить выравнивание:
struct Test2 { uint32_t d; uint16_t f; uint8_t c; uint8_t e; } MyStruct;
Теперь sizeof(MyStruct) сокращается до 8 байт — ценная экономия в памяти-ограниченной прошивке.

Рисунок 3. Выравнивание данных может добавлять заполнение в память структуры.
Резюме
- Структуры позволяют объединить разнородные переменные в единый управляемый блок, улучшая ясность и эффективность кода.
- Пользовательские структуры данных поддерживают задачи вроде межустройственного обмена сообщениями и хранения сенсорных данных.
- Они необходимы для отображения аппаратных регистров в memory-mapped периферии.
- Переупорядочивание членов с учетом выравнивания может значительно уменьшить размер структуры.
Изучите больше наших уроков по встроенному C здесь.
Встроенный
- Что такое рефрактерные металлы? Экспертный обзор их свойств и применений
- Палубные винты (Deck Screws): виды, преимущества и сравнение с деревянными винтами
- Пружинно-энергизированные уплотнения (spring-energized seals): конструкция, функция и промышленные преимущества
- Деревянные винты (Wood Screws): типы, особенности и советы по выбору
- Сплавы стали: типы, состав и применение
- Использование данных в Интернете надежности: стратегии эффективного управления
- Структуры данных в Java: основные классы и Collections Framework
- Промышленный интернет вещей (IIoT): определение, область и промышленное влияние
- Данные технического обслуживания: ключ к надежному управлению активами
- Современное столярное дело: тренды, технологии и техники