Почему ~ (правда ^ правда) не правда? Булевы операторы (отрицание) работают для `unsigned char`s, но не для bools? (C ++)

Я слышал, что часто «все», кроме 0, правда. Но сейчас со мной происходят очень странные вещи … или я просто думаю, что делаю это правильно, а я нет. Вот что происходит:

Когда я хочу проверить, если эквивалентно б, я могу использовать NOT(a XOR b), Когда я проверил это для unsigned chars, все было хорошо, например

unsigned char a = 5;
unsigned char b = 3;
unsigned char c = ~(a^b);

дал мне c == 249:

является: 000001015

б является: 00000011, что составляет 3.

~ (А ^ Ь) является: 11111001, что составляет 249.

Теперь давайте попробуем это с bool«S.

cout << ~(true^true) << ~(true^false) << ~(false^true) << ~(false^false) << endl;
cout << ~(~(true^true)) << ~(~(true^false)) << ~(~(false^true)) << ~(~(false^false)) << endl;

if (~(true^true) == true)
cout << "true";
else
cout << "false";

Это дает мне в консоли:

-1-2-2-1
0110
false

пока я ожидал, что первая строка будет:

1001

Спросив друга, он посоветовал мне попробовать ! вместо ~ и посмотреть, будет ли это работать правильно. И (я думаю) теперь это работает правильно. Но я не понимаю почему. Не должно ли логическое отрицание работать на bools?

5

Решение

Я слышал, что часто «все», кроме 0 это правда

Это действительно для условий, как, например, в операторе if (здесь и ниже я цитирую Стандарт C ++)

Значение условия, которое является выражением, является значением
выражение, контекстно преобразованное в bool для операторов, отличных от
переключатель

Например, если вы напишите как

if (~(true^true) )
cout << "true";
else
cout << "false";

вместо вашего фрагмента кода

if (~(true^true) == true)
cout << "true";
else
cout << "false";

или когда оператор логического отрицания ! используется

9 Операнд оператора логического отрицания! контекстуально
преобразован в bool (пункт 4); его значение истинно, если преобразованный
операнд ложный и ложный в противном случае. Тип результата — bool

Что касается оператора == затем

6 Если оба операнда имеют арифметический или перечислимый тип, обычный
арифметические преобразования выполняются для обоих операндов; каждый из
операторы должны выдавать true, если указанное соотношение истинно и
ложь, если это ложь.

Это в случае

if (~(true^true) == true)

применяется обычное арифметическое преобразование, то есть булево значение true преобразуется в целочисленное значение 1, и оно не равно выражению левого оператора, потому что внутреннее двоичное представление левого операнда отличается от 1, как показано в выводе вашего первого фрагмента кода. ,

4

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

Вы недооцениваете арифметические преобразования. Когда ты сказал ~e для некоторого выражения e целочисленного типа, значение сначала повышается по крайней мере доintи то же самое для e1 ^ e2 (и для любых арифметических выражений, в этом отношении). Так true ^ true первый операнды повышены до int, уступая 1 ^ 1, который действительно равен 0, и, таким образом, вы в конечном итоге ~0, который на вашей платформе -1,

Вы можете смутно осмыслить свою работу, преобразовав результат обратно в bool:

std::cout << static_cast<bool>(~(true ^ true))

В вашей последней проблеме, так как у вас есть выражение с == оператор, в котором два операнда имеют разные типы, оба операнда переводятся в общий тип, который снова int, а также -1 отличается от 1, Опять же, вы можете преобразовать оба операнда в bool сначала получить желаемое равенство.


Мета-урок заключается в том, что встроенные в C ++ операторы, действующие на целые числа, действительно работают только на int и шире, но не на любом из более коротких типов (bool, char, short) (и аналогичные соображения применимы к передаче целых чисел через многоточие). Хотя это может иногда вызывать некоторую путаницу, я полагаю, это также немного упрощает языковые правила. Это все часть наследия C в C ++.

9

Учитывая только ваш первый пример,

~(true^true)

Во-первых, операнды ^ повышены до int, так что это эквивалентно

~(1^1)

Тогда xor, равный 1, сам по себе дает битовый шаблон с нулем, который независимо от int представление обозначает значение 0:

~0

Это инвертирует каждый бит в шаблоне битов со всеми нулями для 0, в результате чего получается битовый шаблон со всеми битами 1, например, для 32-битных int,

int( 0xFFFFFFFF )

С теперь почти универсальным представлением формы дополнения до двух целых чисел со знаком это тогда значение -1.

Ваш вывод поэтому

-1
3

~ немного НЕ.

например ~ 0 — 255 для неподписанного символа и 255! = true,

2

Существует разница между логическим отрицанием и побитовым отрицанием. побитовое отрицание переворачивает биты в переменной, а логическое отрицание переворачивает логическое значение, то есть true / false. Рассмотрим, например, число 5, представленное в двоичном виде как 101. Если вы перевернете только биты (~ 5), вы получите 11111010, что не является ложным, потому что только все нули ложны в c ++. Но если вы вычислите (! 5), вы получите все нули, которые будут работать внутри условия.

2