Почему результат unsigned char << unsigned char не является unsigned char - PullRequest
7 голосов
/ 03 января 2012

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

unsigned char value = 0xff; // 1111 1111
unsigned char  = 0x01; // 0000 0001

std::cout << "SIZEOF value " << sizeof(value) << "\n"; // prints 1 as expected
std::cout << "SIZEOF shift " << sizeof(shift) << "\n"; // prints 1 as expected

std::cout << "result " << (value << shift) << "\n"; // prints 510 ???

std::cout << "SIZEOF result " <<  sizeof(value << shift) << "\n"; // prints 4 ???

Я ожидал, что результат будет 1111 1110, но вместо этого я получаю int (?) Со значениемиз 1 1111 1110.

Как можно сдвинуть биты беззнакового символа влево, чтобы обрезать биты и получить результат 1111 1110?

Я пытаюсь сделать следующее:читать серии байтов и интерпретировать их как целые числа различной длины (1-32 бита).

F0        F5
1111 0000 1111 0101 

может быть

0F (first 4 bits)
0F (next 8 bits)
05 (last 4 bits)

Это как-то связано с тем, что арифметикане делается с типами, меньшими, чем int?

Ответы [ 3 ]

9 голосов
/ 03 января 2012

Цитирую некоторые черновики стандарта 2011 года:

5.8 Операторы сдвига [expr.shift]

...

Операнды должны иметь целочисленный или незаданный тип перечисления, и выполняются интегральные преобразования. Тип результата - тип повышенного левого операнда.

и

4.5 Integral Promotions [conv.prom]

Значение типа integer, отличного от bool, char16_t, char32_t или wchar_t, чье целочисленное преобразование rank (4.13) меньше ранга int, который можно преобразовать в значение типа int, если int может представлять все значения типа источника; в противном случае исходное значение prvalue может быть преобразовано в значение типа unsigned. INT

...

Итак, value повышен до int, а тип value << shift является типом повышенного левого операнда, т.е. int.

Вы можете достичь желаемого результата одним из следующих способов:

std::cout << "result " << ((unsigned char)(value << shift)) << "\n";
std::cout << "result " << ((value << shift)&0xff) << "\n";
2 голосов
/ 03 января 2012

Вы можете замаскировать интересующие вас биты:

(value << shift) & 0xff

То, что вы видите, является результатом целочисленного продвижения и является частью языка.Представьте, что вы сочиняете 16-битное целое число из 2-х 8-битных - вам не нужно вручную повышать целое число до более высокой ширины, чтобы получить старший и младший бит в нужном месте, верно?

2 голосов
/ 03 января 2012

Просто приведите его к неподписанному символу:

std::cout << "result " << static_cast<unsigned char>(value << shift) << "\n";

Или используйте побитовое И:

std::cout << "result " << ((value << shift) & 0xFF) << "\n";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...