Просто о структурах и объединениях в Си

Views: 2271


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

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

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

//
struct
{

     int16_t s_CLt;        // данные в формате 16 байт со знаком
     int16_t s_tNd;        // 
     int16_t s_rEL;        // 
     uint8_t s_SEc;        // данные в формате 8 байт без знака (только положит значение)
     uint8_t s_Nin;        // 
     unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение)
     unsigned Freezing :1; // данные в формате 1 байта

}EE; // данные подлежащие хранению в еепром
//

Это будет гарантировано, что данные в памяти будут расположены последовательно и займут 9 байт (если система процессора микроконтроллера 8 битная) или 6 слов (если 16 битная). Один дополнительный байт будут занимать две переменные описанные как Accident и Freezing, они займут соответственно 0 – 1 байт (Accident )  и 2 байт (Freezing).

Обратиться т.е записывать данные и читать можно таким образом, например:

//
// Для записи

    EE.s_CLt = 4562;
    EE.Accident = 2;

// Для чтения

    temp = EE.s_CLt;
    temp1 = EE.s_Nin;
//

Со структурами struct все довольно понятно,  это расположение данных последовательно в памяти и удобный доступ к ним, особенно, если надо писать какие-то флаги управления и потом данные “скопом” передавать через какой либо интерфейс на другое устройство. Но часто возникает необходимость например иметь представление одних и тех же данных и в виде байта (или слова) и в виде бит. Как это сделать, для этого в Си есть гибкий механизм объединения union.

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

Например, мы имеем структуру данных:

//
struct
{

     int16_t s_CLt;        // данные в формате 16 байт со знаком
     uint8_t s_SEc;        // данные в формате 8 байт без знака (только положит значение)
     unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение)
     unsigned Freezing :1; // данные в формате 1 байта

}EE; // 
//

Визуально это выглядит так:

Вся структура занимает 4 байта. EE.s_CLt занимает 2 байта, EE.s_SEc занимает 1 байта, переменные Accident, Freezing (два и и один байт) будут размещены в 4 байте.

Теперь нам, например, необходимо работать с битами переменной s_CLt, можно конечно использовать операциями с битами, например, нам надо контролировать состояние бита 0 в этой переменной мы, можем вычислить так, выполняем побитовое “&” с переменной и в зависимости от состояния операции выполняет если true или falce:

//

    if(EE.s_CLt & 0b0000000000000001) ******;
    else *******;

//

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

//

    if(EE.FLED1) ******;
    else *******;

//

Где EE.FLED1 мы дали имя биту 0 переменной EE.s_CLt, как это сделать? В нашу структуру надо внедрить объединение. Структуры и объединения можно как угодно комбинировать для всевозможного описания данных в памяти для удобной последующей обработки. В нашем варианте это будет выглядеть так:

//
struct
{
    //-
    union
    {
        int16_t s_CLt;      // данные в формате 16 байт со знаком
        struct
        {
            unsigned	FLED1 :1;// название бита 0
            unsigned	FLED2 :1;// название бита 1
            unsigned	FLED3 :1;// название бита 2
            //*****
        };
    };
    
    uint8_t     s_SEc;          // данные в формате 8 байт без знака (только положит значение)
    unsigned    Accident :2;    // данные в формате 2 байта без знака (только положит значение)
    unsigned    Freezing :1;    // данные в формате 1 байта
}EE;    //
//

Переменную s_CLt мы помещаем, в обеднение в котором находиться эта переменная и новая внутренняя структура. Название ни объединению, ни структуре мы не даем. В этом варианте мы сможет обращаясь, например, к EE.FLED1 контролируя или изменяя состояние бита 0 переменной EE.s_CLt.

Как это выглядит визуально.

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

И для окончания, например, мне необходимо обработать эти 4 байка как одно 32 битное слово, как это сделать? Это сделать просто если нашу структур поместить в объединение и добавит в ней нашу 32 битную переменную:

union
{
    struct
    {
        //-
        union
        {
            int16_t s_CLt;      // данные в формате 16 байт со знаком
            struct
            {
                unsigned	FLED1 :1;// название бита 0
                unsigned	FLED2 :1;// название бита 1
                unsigned	FLED3 :1;// название бита 2
                //*****
            };
        };

        uint8_t     s_SEc;          // данные в формате 8 байт без знака (только положит значение)
        unsigned    Accident :2;    // данные в формате 2 байта без знака (только положит значение)
        unsigned    Freezing :1;    // данные в формате 1 байта
    };
    uint16_t s_32bit;               // в ней все наши биты
}EE;    //

Теперь при необходимости можно обратиться к переменной EE.s_32bit и получить все данные или изменить одной операцией.

Визуально это можно представить так:


Файлы для загрузки

Значок

Просто о структурах и объединениях в Си 343.32 KB 165 downloads

Проект с примером организации данных ...


Это может быть интересно

  • Audio-bluetooth modules F-6188 (BK8000L)Audio-bluetooth modules F-6188 (BK8000L)
    Views: 2387Следующий модуль на чипе BK8000L. Заводское обозначение F-6188 также основным производителем не выпускается и отдан на тиражирование. с нижней стороны имеет маркировку В этом варианте мне попалась вроде полноценная …
  • Тестирование модуля генератораТестирование модуля генератора
    Views: 921  Тестирование модуля генератора Настройка, запуск и проверка рабочей частоты на примере PIC18F26K40. PIC18F26K40 Чтобы понять из-за чего зависит производительность микроконтроллера просто надо понять как работает его задающий тактовый …
  • Самый простой индикатор уровня звукового сигналаСамый простой индикатор уровня звукового сигнала
    Views: 6562 Демонстрационный проект создания индикаторов уровня с использованием WS2812B. Изучив этот проект вы сможете  самостоятельно изготавливать и конструировать свои индикаторы уровня звукового сигнала. Дополнительно читайте статью Бегущие огни на …
  • Проект с использованием MCC часть 02Проект с использованием MCC часть 02
    Views: 2407 Когда мы запустили конфигуратор, самое главное понять, что с этим делать и как проверить, то что мы делаем работает или нет. Для начала настроим регистры конфигурации микроконтроллера и настроем …
  • ch-4050 – дифференциальный терморегуляторch-4050 – дифференциальный терморегулятор
    Views: 2036 ch-4050 – это не новая модель, это расширенная версия универсального терморегулятора ch-4000. Различия коснулись в появлении новой функции дифференциального регулирования. Это вид регулирования по разности температур измеренного двумя …
  • Дисплей KD035C-3A подключение и управлениеДисплей KD035C-3A подключение и управление
    Views: 799 Дисплей KD035C-3A производиться компанией SHENZHEN STARTEK ELECTRONIC TECHNOLOGY CO.,LTD Характеристики Параметр Спецификация Единицы измерения Размер дисплея 70.08(H)*52.56(V) (3.5inch) mm Тип дисплея TFT active matrix Цветовая гамма 65K/262K colors Разрешение …
  • WiFi ESP8266 – AT команды связанные с функцией TCP/IP (v.1.6.1)WiFi ESP8266 – AT команды связанные с функцией TCP/IP (v.1.6.1)
    Views: 5230 AT команды связанные с функцией TCP/IP В этом разделе описаны команды которые позволяют устанавливать соединения между серверами и клиентами в сети. Приведено описание команд и примеры их выполнения. …
  • MPLAB® Code Configurator and EncoderMPLAB® Code Configurator and Encoder
    Views: 1564 Еще раз про энкодер… Для некоторых приложений очень удобно и экономически выгодно, для настройки и управления использовать энкодер. Такие энкодеры имеют строенную тактовую кнопку которую можно применить для выбора …
  • LATINO – открытый проект ch-светомузыкиLATINO – открытый проект ch-светомузыки
    Views: 1697   Проект построенный на некоторых принципах ch-светомузыка. Проект ознакомительный предназначен, для самостоятельного построения простого и эффективного светосинтезатора. Вывод осуществляется на ВОУ собранной на драйверах HL1606. Для этого была …
  • Стабилизатор тока для светодиодов SN3350Стабилизатор тока для светодиодов SN3350
    Views: 2714 SN3350 ближайший аналог ZXLD1350 Как собрать готовый вариант, читайте во второй части – http://catcatcat.d-lan.dp.ua/stabilizator-toka-na-sn3350-chast-2/ 40V  драйвер светодиодов с внутренним ключом  SN3350 – импульсный понижающий преобразователь, разработанный для того, чтобы эффективно управлять одним или …


 

Поделись этим!

Catcatcat

catcatcat

Development of embedded systems based on Microchip microcontrollers.

Продолжайте читать

НазадДалее