There's a lot of potential problems with code like this.
Most importantly, you should never use signed integer types like int
when doing bitwise operations. Because you could either end up with unexpected results, or you could end up with undefined/implementation-defined behavior bugs if using operators like <<
>>
on negative value integers.
So step one is to ensure you have an unsigned integer type. Preferably uint32_t
or similar from stdint.h
.
Another related problem is that if you use small integer types in an expression, such as uint8_t
, char
, short
, bool
etc, then they will get implicitly promoted to type int
, which is a signed type. You get that even if you use unsigned char
or uint8_t
. This is the source of many fatal bugs related to the bitwise operators.
And finally, the printf
family of functions is dangerous to use when you need to be explicit about types. While these function have literally zero type safety, they at the same time assume a certain, specific type. If you give them the wrong type you invoke undefined behavior and the program will potentially crash & burn. Also, being variable-argument list functions, they also use implicit promotion of the arguments (default argument promotions) which might also cause unforeseen bugs.
The "strange" output you experience is a combination of doing bitwise ~
on a signed type and printf
expecting an unsigned int
when you give it the %x
conversion specifier.
In order to get more deterministic output, you could do something like this:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t a = 0xAF; // 10101111
uint32_t b = 0xB5; // 10110101
printf("%.8" PRIx32 "\n", a & b); // a & b = 10100101
printf("%.8" PRIx32 "\n", a | b); // a | b = 10111111
printf("%.8" PRIx32 "\n", a ^ b); // a ^ b = 00011010
printf("%.8" PRIx32 "\n", ~a); // ~a = 1....1 01010000
printf("%.8" PRIx32 "\n", a << 2); // a << 2 = 1010111100
printf("%.8" PRIx32 "\n", b >> 3); // b >> 3 = 00010110
return 0;
}