2

我一直在用 C 编写一个程序,将 char 的前 4 位移到末尾,将后 4 位移到开头。对于大多数值,它正常工作,以及反向操作,但对于某些值,如 8、x、y、z,它给出一个 32 位值作为结果。通过打印变量的十六进制值检查的值。谁能解释为什么会这样?

#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;
}
4

4 回答 4

6

o作为参数传递给printf()会导致自动转换为int,这在您的系统上显然是 32 位的。自动转换使用符号扩展,因此如果设置了第 7o位,则转换结果中的第 8-31 位将被设置,这将解释您所看到的。

您可以使用unsigned char而不是char避免这种情况。或传递o & 0xffprintf().

于 2012-06-12T17:43:48.883 回答
3

尝试将您的变量声明为unsigned char. 您正在获得高位的符号扩展。

于 2012-06-12T17:38:33.017 回答
2

作为 printf (或任何可变参数函数,或任何没有原型的函数)的参数给出的 char 被提升为 int。如果 char 在您的平台上签名并且传递的值为负,则扩展符号。

于 2012-06-12T17:43:43.050 回答
2

您的值被打印为 32 位值,因为您的格式说明符%x告诉printf将值打印为unsigned int. 要将其打印为,您需要带有长度修饰符unsigned char的格式说明符。如果值为正,则对打印输出没有影响,但对于负数则有影响,因为它们设置了最高有效位。%hhxhh

对于下文,解释该代码中如何出现负值,我假设CHAR_BIT == 8负整数的二进制补码表示。

对于班次, 的值o提升为int。如果设置了原始值的第四个最低有效位(如果(o & 8) != 0),则在第一次交换半字节后,设置 的最高有效位o。如果char默认情况下在您的平台上签名,则意味着结果是否定的。对于第二个半字节交换, 的值o再次提升为int,从而产生负值。负值的右移是实现定义的,所以

o=o>>4;

在这种情况下是不可移植的(尽管实际上所有实现都使用算术右移[带符号扩展]或逻辑右移[从左移零])。

在对负整数进行算术移位的实现中,o将设置 的四个最高有效位,因此

o=o|(f<<4);

不再改变值。

可移植地修复代码以获得所需行为的唯一方法是按照 Ned 的建议声明o为 an 。unsigned char那么所有的价值观都是积极的,并且转变的行为是明确的并且符合您的期望。

于 2012-06-12T17:59:14.287 回答