Properrr
@Properrr

Как парсить структуры с битовыми полями в С?

Ребята, есть структура:
void* p = 02b05e1fa6c10000e997f00002e997f01209040919e5030904093be506090409cde52404e998f0180a046974610009040919e5030904093be506090409cde52404e992f0180a04756e640009040919e5030904093be506090409cde52416a00e13;


97 байт.

Описал первую часть заголовка структурой с битовыми полями:
typedef struct Bits_
{
        unsigned  tableID                    : 8;
        unsigned  SectionSyntaxIndicator     : 1; 
        unsigned  Reserved1                  : 1;
        unsigned  Reserved2                  : 2; 
        unsigned  SectionLength              : 12; 
        unsigned  ProgramNumber              : 16;
        unsigned  Reserved3                  : 2;  
        unsigned  VersionNumber              : 5;
        unsigned  CurrentNextIndicator       : 1;  
        unsigned  SectionNumber              : 8;
        unsigned  LastSectionNumber          : 8;
        unsigned  Reserved4                  : 3;  
        unsigned  PCRPid                     : 13;  
        unsigned  Reserved5                  : 4; 
        unsigned  ProgramInfoLength          : 12;                                     
} Bits;


Пытаюсь получить доступ к нужным мне битам:
Bits *pmtFields = reinterpret_cast<Bits*>(data);
printf("tableID=%.2X\n", pmtFields->tableID);
    printf("SectionSyntaxIndicator=%.2X\n", pmtFields->SectionSyntaxIndicator);
    printf("Reserved1=%.2X\n", pmtFields->Reserved1);
    printf("Reserved2=%.2X\n", pmtFields->Reserved2);
    printf("SectionLength=%.2X\n", pmtFields->SectionLength);
    printf("ProgramNumber=%.2X\n", pmtFields->ProgramNumber);
    printf("VersionNumber=%.2X\n", pmtFields->VersionNumber);
    printf("CurrentNextIndicator=%.2X\n", pmtFields->CurrentNextIndicator);
    printf("SectionNumber=%.2X\n", pmtFields->SectionNumber);
    printf("LastSectionNumber=%.2X\n", pmtFields->LastSectionNumber);
    printf("Reserved4=%.2X\n", pmtFields->Reserved4);
    printf("PCRPid=%.2X\n", pmtFields->PCRPid);
    printf("Reserved5=%.2X\n", pmtFields->Reserved5);
    printf("ProgramInfoLength=%.2X\n", pmtFields->ProgramInfoLength);


Вывод:

tableID=02 - правильно!
SectionSyntaxIndicator=00 -Должна быть 1
Reserved1=00 -Должен быть 0
Reserved2=00 -Неважно
SectionLength=5EB -должно быть 5E
ProgramNumber=C1A6 Должен быть 1FA6
VersionNumber=00 Ну и так далее....
CurrentNextIndicator=00
SectionNumber=00
LastSectionNumber=E9
Reserved4=07
PCRPid=1E12
Reserved5=00
ProgramInfoLength=902
SectionSyntaxIndicator=00
Reserved1=00
Reserved2=00
SectionLength=F5E


Котаны, подскажите, че не так? :)

p.s. вот ссылка на полное описание структуры:
www.etherguidesystems.com/help/sdos/mpeg/syntax/ta...
  • Вопрос задан
  • 2738 просмотров
Решения вопроса 1
@MarkusD
все время мелю чепуху :)
Так. Для начала...
void* p = 02b05e1...

SectionSyntaxIndicator=00 -Должна быть 1


Первые 8 бит отходят к "unsigned tableID", все норм. А потом в описании идет однобитовый "unsigned SectionSyntaxIndicator".

Значение второго байта == 0xB0, его первый бит == 0 и в результате все нормально.
Первые 4 бита 0xB0 равны 0, поэтому все следующие ("SectionSyntaxIndicator", "Reserved1", "Reserved2") поля будут равны 0 ибо это первые четыре бита этого же самого байта.

Поле "SectionLength" занимает 12 бит, стало быть оно захватывает вторые 4 бита из 0xB0 и весь байт 0x5E. Поэтому все правильно что оно тебе пишет 0x5EB.

Теперь. Про битовые поля в структурах.
habrahabr.ru/post/142662

После этой ссылки я даже не знаю, что еще от себя писать.
В целом, программа тут ни в чем не виновата, просто, по видимому, ты сам забыл что в шестнадцатиричном представлении байта пишется сперва старший квартет бит, а потом младший. Весной это бывает. :)
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@DancingOnWater
Японский Городовой прав в том, что компилятор будет заниматься выравниванием и все ваши ошибки отсюда. А вот в остальном он не прав.
Ответ написан
@Eddy_Em
Так не годится делать. Чуть только архитектуры будут различаться, как получится черт-те что!
Битовые поля - это страшное наследие 8-битных микроконтроллеров! Только там им и место!!!
А если хочется извращений, то хотя бы используйте стандартные типы (вместо unsigned надо писать uint16_t или uint32_t, смотря что под этим подразумевается) и обязательно упаковывайте структуру, т.к. по умолчанию gcc разместит ее члены с наилучшим выравниванием. Компилятор-то не в курсе, что вам подряд нужно..
Ответ написан
megat72
@megat72
Программист-разработчик
Проблема с этой структурой в том, что ее битовые поля не укладываются на границах unsigned (даже с учетом того, что Data structure alignment будет выставлен на 4 байта)

Например, ProgramNumber находится по смещению 24 бита, но его размер - 16 бит. Компилятор в таком случае просто вынужден сместить ProgramNumber вперед на 8 бит, в седующий unsigned.

ProgramInfoLength - со смещением 28 бит аналогично не может быть размещен по этому смещению, т.к. его размер превышает 4 бита, поэтому компилятор сдвигает его вперед на 4 бита.

В итоге, структура не может занимать менее четырех unsigned.
Если Вы хотите использовать ее для обхода исходной битовой строки "02b05e1fa6c1...", придется эту строку изрядно расширить (дополнительно по 32 бита на каждый блок):
  1. добавить 8 бит padding'а по смещению 24 бита
  2. добавить 4 бита padding'а по смещению 32 + 32 + 28 бит
  3. добавить 20 бит padding'а по смещению 32 + 32 + 32 + 12 бит

И повторять эту процедуру для каждого блока
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы