I've been struggling with some low-level messaging for quite some time and it turned out to be an issue with the checksum calculation. I thought the bitwise XOR operator didn't care about sign, so I was using a QByteArray
to store the bytes, and using the at
method, that returns a char
, to calculate the checksum. The messages were properly acknowledged sometimes, but not always.
Looks like the guys on the other end were using uint8_t
to store the bytes, and
the checksum was failing in some situations. I solved it by casting the char
to uint8_t
, but I'm seriously baffled about that.
Why does the bitwise XOR operator care about sign? I thought it worked on a bit-level, regardless of what they represented. Here's a piece of code I've used to try to understand it.
#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;
}
Even tho both integers hold the same bits, the operation yields different results in each case.
First of all you have to remember that it's implementation-defined if char
is signed or unsigned.
Then you have to remember that values of smaller types like char
or uint8_t
are promoted to int
(or possibly unsigned int
) when used in expressions. This promotion brings with it sign extension of signed types.
So if char
is signed, the value 0b10010101
will be promoted to 0b11111111111111111111111110010101
(using two's complement for negative numbers). Which is very different from the unsigned value 0b00000000000000000000000010010101
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With