Я удивлен поведением 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
?
Полный код Вот
Интегральные продвижения выполняются на операнде ~
мы можем увидеть это, перейдя к проект стандарта 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. Мы не знаем ни о каких системах, на которых это действительно происходит.
Ответ о комплексном продвижении правильный.
Вы можете получить желаемые результаты, приведя и отметив в правильном порядке:
assert(static_cast<unsigned char>(0xAAu) == static_cast<unsigned char>(~0x55u));
Вы можете «усечь» первые 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