问题
I've been writing a program in C to move the first 4 bits of a char to the end and the last 4 to the start. For most values it works normally, as well as the reverse operation, but for some values, as 8, x, y, z, it gives as result a 32 bit value. Values checked through printing hex value of the variable. Can anybody explain why this is happening?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char o, f,a=15;
scanf("%c",&o);
printf("o= %d\n",o);
f=o&a;
o=o>>4;
printf("o= %d",o);
o=o|(f<<4);
printf("o= %x, size=%d\n",o,sizeof(o));
f=o&a;
o=o>>4;
printf("o= %d",o);
o=o|(f<<4);
printf("o= %x, size=%d\n",o,sizeof(o));
return 0;
}
回答1:
Passing o
as an argument to printf()
results in an automatic conversion to int
, which is apparently 32-bit on your system. The automatic conversion uses sign-extension, so if bit 7 in o
is set, bits 8-31 in the converted result will be set, which will explain what you are seeing.
You could use unsigned char
instead of char
to avoid this. Or pass o & 0xff
to printf()
.
回答2:
Try declaring your variables as unsigned char
. You are getting a sign-extension of the upper bit.
回答3:
A char given as argument to printf (or any variadic function, or any function without prototype) is promoted to int. If char is signed on your platform and the passed value is negative, the sign is extended.
回答4:
Your values are printed as 32-bit values because your format specifiers %x
tell printf
to print the value as an unsigned int
. To print it as an unsigned char
, you need the format specifier %hhx
with the hh
length modifier. If the values are positive, that makes no difference for the printed output, but for negative numbers it does because they have the most significant bit set.
For the following, explaining how negative values arise in that code, I assume CHAR_BIT == 8
and twos complement representation for negative integers.
For the shifts, the value of o
is promoted to int
. If the fourth least significant bit of the original value was set (if (o & 8) != 0
), after the first swap of the nibbles, the most significant bit of o
is set. If char
is by default signed on your platform, that means the result is negative. For the second nibble-swap, the value of o
is again promoted to int
, resulting in a negative value. The right-shifting of negative values is implementation-defined, so
o=o>>4;
is not portable in that case (although, in practice all implementations use either an arithmetic right shift [with sign-extension] or a logical right shift [shifting in zeros from the left]).
On implementations doing an arithmetic shift on negative integers, the four most significant bits of o
will all be set, so
o=o|(f<<4);
doesn't change the value anymore.
The only way to portably fix the code to obtain the desired behaviour is to declare o
as an unsigned char
as suggested by Ned. Then all values are positive and the behaviour of the shifts is well-defined and matches your expectations.
来源:https://stackoverflow.com/questions/11001843/bitwise-operation-on-char-gives-32-bit-result