Бит со сдвигом и странности указателя в C, ищите объяснения - PullRequest
2 голосов
/ 16 мая 2010

Я обнаружил нечто странное, что не могу объяснить. Если кто-то здесь может увидеть, что или почему это происходит, я хотел бы знать. То, что я делаю, берет беззнаковый шорт, содержащий 12 битов, выровненных по максимуму, вот так:

1111 1111 1111 0000

Затем я хочу сместить биты так, чтобы каждый байт в короткой позиции удерживал 7 бит с MSB в качестве пэда. Результат, представленный выше, должен выглядеть следующим образом:

0111 1111 0111 1100

То, что я сделал, это:

unsigned short buf = 0xfff;
//align high
buf <<= 4;

buf >>= 1;
*((char*)&buf) >>= 1;

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

0111 1111 1111 1100

Очень странно. Если я использую неподписанный символ в качестве временного хранилища и сдвигаю его, то он работает, например:

unsigned short buf = 0xfff;
buf <<= 4;

buf >>= 1;
tmp = *((char*)&buf);
*((char*)&buf) = tmp >> 1;

Результат этого:

0111 1111 0111 1100

Есть идеи, что здесь происходит?

Ответы [ 2 ]

4 голосов
/ 16 мая 2010

Да, похоже, char подписано на вашей платформе. Если бы вы сделали *((unsigned char*)&buf) >>= 1, это сработало бы.

1 голос
/ 16 мая 2010

Давайте разберемся с этим. Я предполагаю, что ваш компилятор думает о коротком как о 16-битной памяти.

unsigned short buf = 0xfff; 
//align high 
buf <<= 4; 

эквивалентно:

unsigned short buf = 0xfff0;

... и

buf >>= 1; 

должно привести к тому, что buf будет иметь значение 0x7ff8 (т.е. биты сдвинуты вправо на один бит). Теперь для вашей модной линии:

*((char*)&buf) >>= 1; 

здесь много лотов ... сначала нужно разрешить левую сторону. То, что вы говорите, это взять buf и рассматривать его как указатель на 8-битную память (в отличие от ее естественных 16-битных). Какой из двух байтов, на которые первоначально ссылался buf, зависит от того, что такое порядковый номер вашей памяти (если это big-endian buf, указывает на 0x7f, если это little-endian buf указывает на 0xf8). Я предполагаю, что вы используете Intel, что означает его младший порядок, и теперь положительный эффект указывает на 0xf8. Тогда в вашем утверждении говорится, что присваивать этому байту значение этого байта смещается (и знак расширяется, так как char подписан) вправо на единицу, или 0xfc. Другой байт останется неизменным. Если вы не хотите расширять знак, возьмите часть (символ без знака *).

...