I ran across the following example program and I don't exactly understand it's output:
#include <stdio.h>
int main( void ) {
unsigned char i, m =0xFF, n=0x1;
for ( i = 0; i != 8; i++,n+=n, m/=2 )
printf("%5x %5x %5x %5x %5x %5x\n", n,m,n&m,n|m,n^m,~n);
return 0;
}
It prints out:
1 ff 1 ff fe fffffffe
2 7f 2 7f 7d fffffffd
4 3f 4 3f 3b fffffffb
8 1f 8 1f 17 fffffff7
10 f 0 1f 1f ffffffef
20 7 0 27 27 ffffffdf
40 3 0 43 43 ffffffbf
80 1 0 81 81 ffffff7f
The problem is that last column. Since it's unsigned char I would expect it to print out just 2 places in every column. ~n
produces an unsigned char as it's result, but it seems like it's being cast to a signed 32 bit value and sign extended by the %5x
specifier.
How is that possible, what's going on here?
unsigned int x; then 'x' can take values from 0 to 4,294,967,295 (since 'x' is now an unsigned variable). It is not necessary to give signed keyword to any variable because all the variables are signed by default. In printf, %d is used for signed integers whereas %u is used with unsigned integers.
%d is a signed integer, while %u is an unsigned integer. Pointers (when treated as numbers) are usually non-negative. If you actually want to display a pointer, use the %p format specifier.
%u. It is used to print the unsigned integer value where the unsigned integer means that the variable can hold only positive value.
Integer types are promoted when they are used in arithmetic operations (this has nothing to do with printf
, by the way).
So, for example,
unsigned char x = 0xff;
int y = ~x; // x is promoted to 0x000000ff, then changed to 0xffffff00
unsigned char z = ~x; // truncated back to 0x00
Integer promotion causes various problems:
unsigned char x = 1;
if (x << 8)
puts("x << 8 is true"); // does print
x <<= 8;
if (x)
puts("x <<= 8 is true"); // does not print
The two ways to truncate things are casting and masks. Use whatever you prefer.
unsigned char x = 0xab;
printf("x = %02x\n", (unsigned char) x);
printf("x = %02x\n", x & 0xff);
Integer promotion doesn't always happen, and it's not the only kind of implicit cast. It's also a bit subtle and the exact rules are difficult to remember. You only really need to worry about it if you're working with 64-bit numbers, because 1U << 32
could end up being 0
or 1
or something else entirely. (It's often 1
on x86).
The issue is that it's promoted to an int when you pass it into printf's varags - as in Dietrich's answer - when you negate it.
Unfortunately you'll need to strip it down to a byte to pass in, i.e. (~n & 0xff)
.
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