Инициализация объединения

Тема в разделе "Arduino & Shields", создана пользователем Vovka, 3 дек 2020.

  1. Vovka

    Vovka Гик

    Пробовал разными вариантами объявлять объединение и инициализировать, но все не то:
    Код (C++):
    typedef struct PROGMEM
    {
        union{
            unsigned char uParam[6];
            float fParam[2];
        };
    } DataParam;
    DataParam mFloat={ (float)-50.0, (float)150.0 };
     
    На последнюю строчку ругается:
    инициализация: преобразование "float" в "unsigned char", возможна потеря данных
    Как победить?
     
  2. Andrey12

    Andrey12 Гик

    Ну все правильно, с каких пор unsigned char стал дробным?
    И если uParam[6] и fParam[2] то вроде как надо
    DataParam mFloat={{1,4,8,1,21,99}, {1.1,3.14}};

    О и еще увидел typedef struct PROGMEM
    а точно если уже объявил в PROGMEM то потом можно что то еще делать?
     
    Последнее редактирование: 3 дек 2020
  3. Vovka

    Vovka Гик

    а для чего 'union'?
     
  4. Код (C++):
    typedef struct DataParam_t {
        union{
            unsigned char uParam[6];
            float fParam[2];
        };
        DataParam_t(float a, float b) {
          fParam[0] = a;
          fParam[1] = b;
        }
    } DataParam;
    DataParam mFloat((float)-50.0, (float)150.0);
     
  5. Vovka

    Vovka Гик

    использовать как константы нельзя?
     
    Andrey12 нравится это.
  6. Andrey12

    Andrey12 Гик

    Мне самому интересно. Може кто ответит.
     
  7. Vovka

    Vovka Гик

  8. Vovka

    Vovka Гик

    А где PROGMEM ? ;)
     
  9. Дал ответ как победить.
     
    Andrey12 нравится это.
  10. Vovka

    Vovka Гик

    Мне нужно чтоб на этапе компиляция инициализация делалась, а не на этапе выполнения!
     
  11. Инициализатору, заключенному в скобки, доступен только первый член объединения.
    Можете убедиться поменять местами члены.
    Код (C++):

    typedef struct {
        union{
            float fParam[2];
            unsigned char uParam[6];
        };
    } DataParam;
    DataParam mFloat = {
        (float)-50.0, (float)150.0
    };
    Для случая DataParam PROGMEM mFloat это не прокатит,
    Код (Text):
    sketch_dec03a:7:19: error: variable 'mFloat' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
    DataParam PROGMEM mFloat = {
                       ^~~~~~
    т.е. инициализатор будет вызываться в коде.
     
  12. Vovka

    Vovka Гик

     
  13. b707

    b707 Гуру

    размер данных разного типа в обьединении должен совпадать, иначе компилятор не будет знать, как преобразовать одно в другое.
    А у вас?
    Два float - это 4х2 = 8 байт
    А 6 char - это 6 байт...

    Сделайте массив char длиной 8 элементов - ошибки не будет.
     
  14. b707

    b707 Гуру

    непосредственно инициализировать унион в прогмеме у меня не получилось, только через промежуточную структуру
    Но вот так все работает:
    Код (C++):

    // описываем union
    typedef struct  DataParam_t
    {
        union{
            unsigned char uParam[8];
            float fParam[2];
        };
    } DataParam;

    // описываем вспомогательную структуру, через которую будем инициализировать union
    typedef struct
    {
       float ff[2];
    }  DataParam_f;
     
    // инициализируем
    const DataParam_f mFloat PROGMEM = { -50.0, 150.0 };

     
    Опять же, обратится к этим данным именно как унион непосредственно из прогмем не выйдет, нужно сначала скопировать их в локальную структуру
    Код (C++):
    void setup() {
    Serial.begin(9600);
    // выгрузка данныхиз прогмем в локальную структуру
    DataParam temp_str;
    memcpy_P( &temp_str, &mFloat, sizeof(DataParam));
    Serial.println(temp_str.fParam[0]);
    }
     
    Вывод = если таких данных в программе много - может и имеет смысл, а если один-два экземпляра - то проще в оперативке хранить

    Если кто может сделать это красивее - показывайте, интересно
     
    Последнее редактирование: 4 дек 2020
  15. b707

    b707 Гуру

    ну как раз эту ошибку очень легко обойти, если инициализировать через список
    Код (C++):
    typedef struct  DataParam_t
    {
        union{
            const unsigned char uParam[8];
            const float fParam[2];
        };
        DataParam_t(float a, float b): fParam{a,b}  {}
    } DataParam;
    const DataParam PROGMEM mFloat( -50.0, 150.0 );
    все отлично компилируется, только не работает :)
     
  16. b707

    b707 Гуру

    И еще добавлю - вообще, чтобы обращаться к массиву float ff[2] как в двум флоат или как к восьми байтам - вообще никакой унион не нужен.
    Достаточно приведения типов.
    И для случая ПРОГМЕМ это, пожалуй, самый простой и короткий вариант
     
    Vovka нравится это.