Битовая манипуляция — побитно не из uchar выдает int

Я удивлен поведением C ++ при применении побитового метода к неподписанному символу.

Принять двоичное значение 01010101b, который 0x55, или же 85, Применение побитового, а не восьмибитного представления должно дать 10101010b, который 0xAA, или же 170,

Однако я не могу воспроизвести вышеизложенное в C ++. Следующее простое утверждение не выполняется.

assert(static_cast<unsigned char>(0xAAu) == ~static_cast<unsigned char>(0x55u));

Я напечатал значения 0x55, 0xAA, а также ~0x55 (как учар) со следующим кодом. И это показывает, что побитовое не делает не то, что я ожидаю.

std::cout << "--> 0x55: " << 0x55u << ", 0xAA: " << 0xAAu << ", ~0x55: "<< static_cast<unsigned>(~static_cast<unsigned char>(0x55u)) << std::endl;

--> 0x55: 85, 0xAA: 170, ~0x55: 4294967210

Номер, который напечатан для ~0x55 равно 11111111111111111111111110101010b, который является 32-битным побитовым не 0x55, Итак ~ Оператор работает с 32-разрядными целыми числами, даже если я явно приведу ввод к unsigned char, Это почему?

Я применил еще один тест, чтобы увидеть, какой тип ~ Оператор возвращает. И это оказывается int на unsigned char вход:

template <class T>
struct Print;

// inside main()
Print<decltype(~static_cast<unsigned char>(0x55))> dummy;

Возвращает следующую ошибку компилятора, которая указывает, что результат имеет тип int,

error: implicit instantiation of undefined template 'Print<int>'
Print<decltype(~static_cast<unsigned char>(0x55u))> dummy;

Что я делаю неправильно? Или как мне получить C ++ для производства 0xAA от ~0x55?

Полный код Вот

7

Решение

Интегральные продвижения выполняются на операнде ~ мы можем увидеть это, перейдя к проект стандарта C ++ раздел 5.3.1 Унарные операторы который говорит (акцент мой):

Операнд ˜ должен иметь целочисленный или незаданный тип перечисления;
результат — дополнение его операнда. Интегральные акции
выполняются.
Тип результата — это тип повышенного операнда […]

и интегральные акции рассматриваются в разделе 4.5 Интегральные акции и скажи:

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

Для полноты, чтобы увидеть, что символ без знака ранг меньше, чем ранг ИНТ мы можем пойти в раздел 4.13 Целочисленный конверсионный рейтинг который говорит:

Ранг целого типа со знаком должен быть больше, чем ранг
любой целочисленный тип со знаком меньшего размера.

а также:

Ранг чар равняется званию подписанного чарса и без знака
голец.

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

Как отмечает Бен Фойгт, было бы целесообразно иметь систему, в которой sizeof (int) == 1 а также CHAR_BIT >= 32, В этом случае ранг неподписанного символа не должен быть меньше, чем int, и, следовательно, повышение будет равняться unsigned int. Мы не знаем ни о каких системах, на которых это действительно происходит.

9

Другие решения

Ответ о комплексном продвижении правильный.

Вы можете получить желаемые результаты, приведя и отметив в правильном порядке:

assert(static_cast<unsigned char>(0xAAu) == static_cast<unsigned char>(~0x55u));
2

Вы можете «усечь» первые 1, присваивая результат ~0x55 для unsigned char:

#include <iostream>

int main()
{
unsigned char input = 0x55;
unsigned char output = ~input;

std::cout << "input: " << (int)input << " output: " << (int)output << std::endl;

return 0;
}

Результат:

input: 85 output: 170
1
По вопросам рекламы [email protected]