When you begin manipulating bits, one of the biggest pitfalls people fall into is twiddling bits on signed data types. That is problematic due to several issues.
Take for example what occurs when you declare char c = 127;
c = 01111111;
and then do c += 1;
. 128
cannot be represented by a signed char
. If you look at the bits of c
as a short, you see:
c = 1111111110000000; (-128 signed, 65408 unsigned)
If an unsigned type had been used for c
, then sign extension does not apply. Moreover, bit operations on a signed type is implementation defined (same section of the standard), meaning how the conversion is handled is up to you, it is not specified by the C standard. So if you want well-defined behavior, limit bit manipulation to unsigned types.
(you are free to check the bits of signed types (e.g. to determine sign, even/odd, etc..), all of which are defined, but changing values of signed types by bit manipulation is implementation defined -- by you)
If you read the comments, using variables of exact width is important when you start fiddling with bits. stdint.h
contains the exact width types (e.g. uint32_t
guarantees a 32-bit unsigned value). inttypes.h
provides macros you can use to read/print exact widths with scanf
, printf
, etc.., e.g.:
uint32_t bit;
printf ("Enter bit to change (0-31): ");
if (scanf ("%" SCNu32 "%*c", &bit) != 1 || bit > 31u) {
fprintf (stderr, "error: invalid conversion or value for bit.\n");
return 1;
}
Printing exacts widths works in similar manner:
printf ("bit : %" PRIu32 "\n", bit);
A very readable summary is Fixed width integer types (since C99).
The moral of the story is that you need to take a bit of care when manipulating bits, especially on signed types, because there are a number of pitfalls that await the unwary. There is absolutely nothing wrong with bit manipulations, there is a large body of efficient code out there that makes extensive use of them, but you have to make sure you avoid the subtle issues associated with them. (not to mention with modern processors, compilers, optimizations, gobs of memory, etc.. there are diminishing gains associated with them)
Hopefully this was helpful. Let me know if you have further questions.