Почему побитовый оператор XOR C / C++ заботится о знаке? [дубликат]


На этот вопрос уже есть ответ здесь:

Я довольно долго боролся с некоторыми низкоуровневыми сообщениями, и это оказалось проблемой с вычислением контрольной суммы. Я думал, что побитовый оператор XOR не заботится о знаке, поэтому я использовал QByteArray для хранения байтов и использовал метод at, который возвращает char, чтобы вычислить контрольную сумму. Иногда сообщения были должным образом подтверждены, но не всегда.

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

Почему побитовый оператор XOR заботится о знаке? Я думал, что это работает на уровне битов, независимо от того, что они представляют. Вот фрагмент кода, который я использовал, чтобы попытаться понять его.

#include <stdio.h>
#include <stdint.h>
#include <iostream>
#include <bitset>

int main ()
{    
    uint8_t a = 0b10010101;
    char b    = 0b10010101;

    uint32_t checksum;

    checksum = 55;
    checksum ^= a;
    std::cout << std::bitset<32>(checksum) << std::endl;

    checksum = 55;
    checksum ^= b;
    std::cout << std::bitset<32>(checksum) << std::endl;    
}

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

1 4

1 ответ:

Прежде всего, вы должны помнить, что он определяется реализацией, если char является подписанным или неподписанным.

Тогда вы должны помнить, что значения меньших типов, таких как char или uint8_t, являются повышен в должности to int (или, возможно, unsigned int) при использовании в выражениях. Это продвижение приносит с собой расширение знака подписанных типов.

Таким образом, если char подписано, значение 0b10010101 будет повышено до 0b11111111111111111111111110010101 (используя дополнение two для отрицательных чисел). Который очень отличается от беззнакового значения 0b00000000000000000000000010010101.