Страниц: [1]
  Печать  
Автор Тема: битовые поля - странное поведение  (Прочитано 5668 раз)
igoriy
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« : Июня 14, 2004, 09:50:16 pm »

Странное поведение битовых полей.
Имеется структура:

#pragma pack(1)

typedef struct _blkid Blkid;
typedef struct _devid Devid;
typedef union  _canid Canid;

struct _blkid
{   unsigned int mdfMsg: 8;
    unsigned int codMsg: 8;
    unsigned int   srvc: 4;
    unsigned int adrBlk: 7;
    unsigned int upPrio: 1;
    unsigned int msgBlk: 1;
    unsigned int       : 3;
};

struct _devid
{   unsigned char id0;
    unsigned char id1;
    unsigned char id2;
    unsigned char id3;
};

union _canid
{   Devid dev;
    Blkid blk;
};

входящие сообщение (дамп памяти): F8 1F 12 00

Canid id;

id.dev.id0=0xF8
id.dev.id1=0x1F
id.dev.id2=0x12
id.dev.id3=0x00
Тут все впорядке.

А с Blkid что-то странное:
имеем:  id.blk.msgBlk=0, id.blk.upPrio=0
        id.blk.adrBlk=1, id.blk.srvc=2
        id.blk.codMsg=1F, id.blk.mdfMsg=F8

должно: id.blk.msgBlk=1, id.blk.upPrio=1
        id.blk.adrBlk=1, id.blk.srvc=F
        id.blk.codMsg=12, id.blk.mdfMsg=0

Если в структуре Blkid сделать обратный порядок,
все равно, получается неверно:
будет:  id.blk.msgBlk=1, id.blk.upPrio=1
        id.blk.adrBlk=7F, id.blk.srvc=1
        id.blk.codMsg=12, id.blk.mdfMsg=0

Что можно сделать? Может есть какая-нибудь pragma,
или ключ коммандной строки?

Конечно, можно работать с масками и сдвигами,
или завести временную переменную и каждый раз
id0=id3,id1=id2,id2=id1,id3=id0,
но хочется нормальной работы с битовыми полями.
Для этого они собственно и предназначены.
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #1 : Июня 15, 2004, 05:18:24 am »

В упор не вижу ничего странного. За исключением того, что должно получиться по вашему мнению. Для обратного порядка:


0    0      1    2      1    F      F    8
0000 0000   0001 0010   0001 1111   1111 1000
+++++++++   *********   ++++ **********+ *
 MdfMsg      CodMsg     srvc   adrBlk  | MsgBlk
                                       |
                                       upPrio

Итого MdfMsg=0, CodMsg=0x12, srvc=1, adrBlk=0x7F, upPrio=1, MsgBlk=1
Так у вас и вышло. Для прямого порядка что-то не совсем совпало:


F    8      1    F      1    2      0    0
1111 1000   0001 1111   0001 0010   0000 0000
+++++++++   *********   ++++ **********+ *
 MdfMsg      CodMsg     srvc   adrBlk  | MsgBlk
                                       |
                                       upPrio

MdfMsg=0xf8, CodMsg=0x1f, srvc=1, adrBlk=0x10, upPrio=0, msgBlk=0
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #2 : Июня 15, 2004, 07:22:07 am »

Извините, перепутал - обратный порядок в битовом поле а не в данных. Получается:

  F    8      1    F      1    2      0    0
  1111 1000   0001 1111   0001 0010   0000 0000
     * +********** ++++   *********   +++++++++
MsgBlk |  adrBlk   srvc    CodMsg       MdfMsg
       |
    upPrio

MdfMsg=0, CodMsg=0x12, srvc=0xf, adrBlk=0x01, upPrio=1, msgBlk=1
Действительно что-то не так.
Записан
lestat
QOR.Moderator
*****
Offline Offline

Сообщений: 985


I don't trust anything


Просмотр профиля WWW
« Ответ #3 : Июня 15, 2004, 07:57:06 am »

sizof(struct _blkid) от что выдает ?
Записан

gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #4 : Июня 15, 2004, 08:32:43 am »

Все понял

#pragma pack(1)
struct MyBitField {
  unsigned int b0  :  4;
  unsigned int b1  :  4;
  unsigned int b2  :  4;
  unsigned int b3  :  2;
  unsigned int b4  :  2;
  unsigned int b5  : 16;
  unsigned int b6  : 16;
};

int main() {
  unsigned char Data[] = { 0x12, 0x78, 0x01, 0x02, 0x03, 0x04 };
  unsigned short &A = *reinterpret_cast<unsigned short*>(Data);
  MyBitField &B = *reinterpret_cast<MyBitField*>(Data);

 /* ... */

}

Если расположить разряды, записанные в data от старшего к младшему, получим
04 03 02 01 78 12

Программа выводит:
B.b0=2, B.b1=1, B.b2=8, B.b3=3, B.b4=1, B.b5=201, B.b6=403
Это соответствует порядку, когда первые элементы поля младшим битам, и т.д. Этот порядок не соответствует физическому расположению данных в памяти! Правильно это или нет? Затрудняюсь сказать, пытался найти в Страуструпе - не нашел.
Кстати, заметьте, что размер MyBitField в этом примере больше размера unsigned int - sizeof(MyBitField)=6. И в поле можно писать элементы совершенно разных типов - bool, char, short. Что полностью соответствует стандарту 98 года.
Записан
MikeP
Участник
*
Offline Offline

Сообщений: 6


Просмотр профиля WWW
« Ответ #5 : Июня 15, 2004, 08:39:55 am »


Этот порядок не соответствует физическому расположению данных в памяти! Правильно это или нет?


Это разница в архитектурах big_endian и little endian


 размер MyBitField в этом примере больше размера unsigned int


а для избежания этого можно использовать __attribute__((__packed__))
Записан
igoriy
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #6 : Июня 17, 2004, 09:57:03 pm »

Я не смог понять, как описать структуру с битовыми полями
чтобы получить следующее:

F____8____1____F____1____2____0____0
1111 1000 0001 1111 0001 0010 0000 0000
___* +******* ++++ ******** +++++++
mBlk | adrBlk __ srvc _ CodMsg __ MdfMsg
___upPrio

MdfMsg=0, CodMsg=0x12, srvc=0xf, adrBlk=0x01, upPrio=1, msgBlk=1

to lestat: sizeof(_blkid) = 4 (32 бита).

P.S. В литературе по C написано, что при описании битовых полей первыми должны идти младшие биты.
В действительности получается только если размер стуктуры 8 бит.
Записан
igoriy
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #7 : Июня 17, 2004, 09:57:39 pm »

Как надо писать текст, что бы при просмотре
несколько подряд идущих пробелов не выглядели как один?
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #8 : Июня 18, 2004, 05:05:25 am »

igoriy
Как надо писать текст, что бы при просмотре
несколько подряд идущих пробелов не выглядели как один?

Надо писать в тегах (code) ... (/code), только с квадратными скобками, а не круглыми, как я тут написал
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #9 : Июня 18, 2004, 06:27:20 am »

igoriy
В литературе по C написано, что при описании битовых полей первыми должны идти младшие биты

Да так и было, пока не придумали в 1998 новый стандарт С++. Зато теперь в битовом поле не обязательно должны быть все переменные одного типа, и размер поля определяется не типами элементов, а суммарным количеством бит.

igoriy
Я не смог понять, как описать структуру с битовыми полями чтобы получить следующее

Поскольку adrBlk расположен в младших битах бладшего байта и старших битах старщего, то никак - получается разрыв . Можно только с перестановкой байт местами.

З.Ы. А вот, например, у USB-шного OHCI все регистры 4-байтовые, но нумеруются биты от младшего бита младщего байта к старшему биту старшего байта, и поэтому регистры без проблем описываются битовыми полями
Записан
igoriy
Участник
*
Offline Offline

Сообщений: 0


Просмотр профиля
« Ответ #10 : Июня 20, 2004, 11:02:42 pm »

Вот до кучи интересный момент:

unsigned short newcond = 0x9555;
short oldcond = 0x9555;
if(newcond ^ oldcond)
    {... //вошли сюда =:-[ ]}

Чего ради на побитовую операцию влияет знаковость переменной?
Записан
gleb
Участник
*
Offline Offline

Сообщений: 18


Просмотр профиля
« Ответ #11 : Июня 21, 2004, 06:40:01 am »

igoriy
Чего ради на побитовую операцию влияет знаковость переменной?

С этим рано или поздно сталкивается каждый, кто начал программировать на С
Сам ничего придумывать не буду, перепишу несколько фраз из книжки Б.Страуструпа "Язык программирования С++".
Б.Страуструп
Перед тем, как выполнить арифметическую операцию, используется интегральное продвижение - для того, чтобы создать переменные типа int из переменных более "коротких" целых типов.
...
Продвижения используются как часть обычных арифметических преобразований.
...
Обычные арифметические преобразования выполняются над операндами бинарного оператора, чтобы привести их к общему типу, который потом используется как тип результата.

В результате вашей операции получится 0xffff0000.
Записан
Страниц: [1]
  Печать  
 
Перейти в: