Bitwise operation on char gives 32 bit result

风格不统一 提交于 2021-01-27 17:45:39

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!