На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual C++ / MFC / WTL (далее Раздела)
1) На Раздел распространяются все Правила Форума.
2) Перед тем, как создать новый топик, убедитесь, что Вы читали Правила создания тем в Разделе.
3) Вопросы, не связанные с программированием (настройки MS Visual Studio, книги, библиотеки и т.д.),
обсуждаются в разделе C/C++: Прочее
4) Вопросы разработки .NET (Windows Form, C++/CLI и т.п.) приложений на Visual C++/C# обсуждаются в разделе .NET.
5) Нарушение Правил может повлечь наказание со стороны модераторов.

Полезные ссылки:
user posted image FAQ Раздела user posted image Обновления для FAQ Раздела user posted image Поиск по Разделу user posted image MSDN Library Online
Модераторы: ElcnU
  
> Битовые поля структуры не хотят паковаться
    Решил хитро преобразовывать данные протокола SBUS в байты и обратно. Через объявление структуры и объединение. Но что-то пошло не так... :D
    Значения в одном канале для SBUS есть 11-битное число. Отправка же всех данных по USART идёт побайтно.

    ExpandedWrap disabled
      #pragma pack(push, 1) //
      typedef struct tag_sbus_dat {
          BYTE  StartByte;
          WORD ch0 : 11;
          WORD ch1 : 11;
          WORD ch2 : 11;
          WORD ch3 : 11;
          WORD ch4 : 11;
          WORD ch5 : 11;
          WORD ch6 : 11;
          WORD ch7 : 11;
          WORD ch8 : 11;
          WORD ch9 : 11;
          WORD ch10 : 11;
          WORD ch11 : 11;
          WORD ch12 : 11;
          WORD ch13 : 11;
          WORD ch14 : 11;
          WORD ch15 : 11;
          BYTE  FlagsByte;
          BYTE  EndByte;
      }  SBUS_DAT;
      #pragma pack(pop)
       
      typedef union
      {
          BYTE byte[25];
          SBUS_DAT msg;
      } Sbus_msg;
       
      Sbus_msg Sbus_Data;

    Общее количество бит в структуре должно быть 200, что соответствует 25 байт (размер посылки в SBUS).
    Задумка такая: формирую значения всех 16 каналов, и выбрасываю их на USART в виде 25 байтов.
    И в обратном направлении: Читаю 25 байтов с USART и тут же получаю 11-битные значения всех 16 каналов.

    Но на 10 канале число не соответствует реальному. И размер структуры :
    ExpandedWrap disabled
      printf("sizeof data is %d\n", sizeof(Sbus_Data));

    Вместо 25 байтов выдает 36.

    Где тут засада, не могу понять... :scratch:
      С битовыми полями не все так просто. По стандарту там многое зависит от реализации. Вот кусочек стандарта "Стандарт-Си++ 2017 (ISO-IEC_14882-2017)" (обрати внимание на выделенное красным):
      Цитата

      12.2.4 Bit-fields


      1. A member-declarator of the form

      identifieropt attribute-specifier-seqopt : constant-expression brace-or-equal-initializeropt

      specifies a bit-field; its length is set off from the bit-field name by a colon. The optional attribute-specifier-seq appertains to the entity being declared. The bit-field attribute is not part of the type of the class member. The constant-expression shall be an integral constant expression with a value greater than or equal to zero. The value of the integral constant expression may be larger than the number of bits in the object representation (6.9) of the bit-field’s type; in such cases the extra bits are padding bits (6.9). Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.
      [ Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. —end note ]

      2. A declaration for a bit-field that omits the identifier declares an unnamed bit-field. Unnamed bit-fields are not members and cannot be initialized. [ Note: An unnamed bit-field is useful for padding to conform to externally-imposed layouts. —end note ] As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the value of the constant-expression be equal to zero.

      3. A bit-field shall not be a static member. A bit-field shall have integral or enumeration type (6.9.1). A bool value can successfully be stored in a bit-field of any nonzero size. The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields. A non-const reference shall not be bound to a bit-field (11.6.3). [ Note: If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly. See 11.6.3. —end note ]

      4. If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (10.2), the original enumerator value and the value of the bit-field shall compare equal.


      А вот кусочек из "Стандарт-Си-2018 (ISO-IEC_ 9899-2018)":

      Цитата

      6.7.2.1 Structure and union specifiers
      ...
      11.An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
      ...


      Я попробовал в онлайн-компиляторе твой код, предварительно изменив твои типы на типы из стандартной библиотеки - там все как ты хотел:

      ExpandedWrap disabled
        #include <cstdio>
        #include <cstdint>
         
        #pragma pack(push, 1) //
        typedef struct tag_sbus_dat {
            uint8_t  StartByte;
            uint16_t ch0 : 11;
            uint16_t ch1 : 11;
            uint16_t ch2 : 11;
            uint16_t ch3 : 11;
            uint16_t ch4 : 11;
            uint16_t ch5 : 11;
            uint16_t ch6 : 11;
            uint16_t ch7 : 11;
            uint16_t ch8 : 11;
            uint16_t ch9 : 11;
            uint16_t ch10 : 11;
            uint16_t ch11 : 11;
            uint16_t ch12 : 11;
            uint16_t ch13 : 11;
            uint16_t ch14 : 11;
            uint16_t ch15 : 11;
            uint8_t  FlagsByte;
            uint8_t  EndByte;
        }  SBUS_DAT;
        #pragma pack(pop)
         
        typedef union
        {
            uint8_t byte[25];
            SBUS_DAT msg;
        } Sbus_msg;
         
        int main()
        {
            Sbus_msg Sbus_Data;
            printf("sizeof data is %ld\n", sizeof(Sbus_Data));
            return 0;
        }


      https://onlinegdb.com/Cyn-Rqok-
        Majestio, спасибо.
        У меня стандарт Си++ 17
        Сходил по твоей ссылке. Там вижу реально размер структуры 25 байт.
        Скопировал твой код себе. Запустил - всё равно 35 байтов. >:(
        Использую MSVC 2017.

        Видимо придётся отказаться от хитрого плана и перекодировать всё вручную. <_<
          Цитата DrUnkard @
          Видимо придётся отказаться от хитрого плана и перекодировать всё вручную.

          Думаю, имеет смысл погуглить про особенности именно MSVC 2017.
            Я тут другое поискал. Нашел ручную кодировку / раскодировку SBUS. Буду применять ее и не заморачиваться своими хитростями. :yes-sad:
            Кому интересно - тут Функции:
            ExpandedWrap disabled
              bool SBUS::read(uint16_t* channels, bool* failsafe, bool* lostFrame)
               
              void SBUS::write(uint16_t* channels)

            https://github.com/TheDIYGuy999/SBUS/blob/m...er/src/SBUS.cpp

            Спасибо всем добрым людям. :D
              Цитата Majestio @
              Думаю, имеет смысл погуглить про особенности именно MSVC 2017.

              Ну в догонку ... Мелкомягкие имеют свою точку зрения на упаковку битовых полей.
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script execution time: 0,0316 ]   [ 16 queries used ]   [ Generated: 19.04.24, 03:07 GMT ]