4

I'm trying to do bit arithmetic with variables a and b. When I reverse a, which has the value 0xAF, the result shows as 8 digits. Unlike the others that show as 2 digits.

I don't know why it happens, but guess that it is relevant to %x's showing way and little endian?

Here is my code:

#include <stdio.h>
int main()
{
    int a = 0xAF; // 10101111
    int b = 0xB5; // 10110101

    printf("%x \n", a & b); // a & b = 10100101
    printf("%x \n", a | b); // a | b = 10111111
    printf("%x \n", a ^ b); // a ^ b = 00011010
    printf("%x \n", ~a); // ~a = 1....1 01010000
    printf("%x \n", a << 2);// a << 2 = 1010111100 
    printf("%x \n", b >> 3); // b >> 3 = 00010110 

    return 0;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
Ongbune
  • 43
  • 3

2 Answers2

6

Considering your int a is most likely 32 bit in size, your a actually looks like this:

int a = 0xAF; // 0000 0000 0000 0000 0000 0000 1010 1111

So if you flip all the bits on that, you have

1111 1111 1111 1111 1111 1111 0101 0000

Or, in hex

0xFFFFFF50

Which is exactly what you're getting. The others show only 2 digits because trailing zeroes are omitted when printing hex, and your other bit operations do not in fact change any of the leading zeroes.

---- Credit to @ chqrlie for this ---- If you really only want to see 8 bits of the result, you can do

printf("%hhx \n", ~a); // ~a = 1....1 01010000 --> Output : 50

Which restricts the printed value to unsigned char (8 bit [on modern os, not guaranteed, but very likely for your purposes]) length.

Magisch
  • 7,312
  • 9
  • 36
  • 52
  • @dhke Yes, I just noticed and fixed it a few seconds ago :) – Magisch Feb 01 '16 at 08:38
  • `uint8_t a = 0xAF; ... ~a` would give the very same result so that advise is not good. Proper, bug free code is `printf("%" PRIX32 "\n", ~(uint32_t)a);` – Lundin Feb 01 '16 at 08:45
  • Using a type `uint8_t` will not change anything as the expression is evaluated as `int` anyway. You can use format `%hhx` to print the value restricted to `unsigned char`, most likely 8 bits. – chqrlie Feb 01 '16 at 08:46
  • @Lundin I already added a caveat with credit to your comment in the last part of the answer. – Magisch Feb 01 '16 at 08:46
  • @chqrlie Thanks for the suggestion, I will add that with credit to the answer. – Magisch Feb 01 '16 at 08:47
  • 1
    Also `unsigned char` is **not** guaranteed to be 8 bits, if it is not, type `uint8_t` is probably not present either. – chqrlie Feb 01 '16 at 08:48
  • @chqrlie Are you sure of that? I was always under the impression that sizeof(char) and sizeof(unsigned char) is mandated to be 1 (1 byte == 8 bits)? – Magisch Feb 01 '16 at 08:49
  • 1 byte is not necessarily 8 bits - the no of bits in a `char` is defined in `CHAR_BIT` - better to use `uint8_t`, although you're unlikely to run into problems unless you work on DSPs or other esoteric systems. – Paul R Feb 01 '16 at 08:53
  • @PaulR Wait what? How could 1 byte possibly not be 8 bits? Do you have an example for this? – Magisch Feb 01 '16 at 08:54
  • This has been covered many times on StackOverflow (e.g. http://stackoverflow.com/questions/11600378/portable-code-bits-per-char) - most modern conventional platforms have 1 byte = 8 bits, but it's not universal. In C a `char` is always one byte and is required to have *at least* 8 bits. I know of systems where `CHAR_BIT` can be 9 bits or even 24 bits - and there are probably others. – Paul R Feb 01 '16 at 08:55
  • @Magisch: `sizeof(char)` and `sizeof(unsigned char)` are indeed equal to `1` by definition and type `unsigned char` is mandated to be at least 8 bits, but some architectures do not support 8 bit bytes: bytes there can be 9 bits (some older mainframes) or even 16 or 32 bits (some DSP and embedded calculators), or any size greater than 8. – chqrlie Feb 01 '16 at 09:00
  • See [this section of the Wikipedia entry for "byte"](https://en.wikipedia.org/wiki/Byte#Common_uses) and also note the use of the more accurate term "octet" for an 8 bit byte. – Paul R Feb 01 '16 at 09:02
4

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;
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    For example, `char a = 0xAF; ... a << 2` invokes undefined behavior if `char` is signed. – Lundin Feb 01 '16 at 09:11
  • Your answer was really helpful for me. But i'm a student learning C Language. So there are expssions that i can't understand on your answer. How could i get the information about PRix32 and %.8 and uint32_t? – Ongbune Feb 01 '16 at 12:45
  • @Ongbune `%.8` is a standard printf specifier stating how many digits you want it to print out, regardless of how large the number is. `uint32_t` is one of many fixed-width integers that were introduced to the language with the C99 standard, they are found in the `stdint.h` header, so I would imagine that searching for information about `stdint.h` would give more info. `PRIx32` is a format specifier which can use to `printf` these types - all those format specifiers for the stdint types are found in `inttypes.h`. – Lundin Feb 01 '16 at 13:03
  • Since I knew that `inttypes.h` must include `stdint.h` internally, I sloppily skipped the `#include `. – Lundin Feb 01 '16 at 13:03
  • And yes, the bitwise operators only allow integer types. – Lundin Feb 01 '16 at 13:04
  • Very good explanation. You might add that compiler warnings can help track argument type mismatches for the `printf` and `scanf` families of functions (`gcc -Wall -Wextra` and `clang -Wall -Weverything` – chqrlie Feb 01 '16 at 23:05