打印值0x89时输出奇怪(-119)

时间:2013-07-03 02:33:58

标签: c++ c hex output

正如标题所说,运行以下代码时,我得到一个“奇怪”的结果:

#include <stdio.h>

int main()
{
    char buff[4] = {0x17, 0x89, 0x39, 0x40};
    unsigned int* ptr = (unsigned int*)buff;
    char a = (char)((*ptr << (0*8)) >> (3*8));
    char b = (char)((*ptr << (1*8)) >> (3*8));
    char c = (char)((*ptr << (2*8)) >> (3*8));
    char d = (char)((*ptr << (3*8)) >> (3*8));

    printf("0x%x\n", *ptr);
    printf("0x%x\n", a);
    printf("0x%x\n", b);
    printf("0x%x\n", c);
    printf("0x%x\n", d);

    return 0;
}

输出:

0x40398917
0x40
0x39
0xffffff89
0x17

为什么我没有0x89

3 个答案:

答案 0 :(得分:4)

这是因为您的char变量已签名,并且在升级时会进行符号扩展(在这种情况下升级为更宽的类型)。签名扩展是一种在执行此促销时保留符号的方式,因此-119保持为-119,无论是8位,16位还是更宽的类型。

您可以通过显式使用unsigned char来解决此问题,因为至少在C中,char是有符号还是无符号是特定于实现的。来自C11 6.2.5 Types /15

  

实现应将char定义为与signed char或unsigned char具有相同的范围,表示和行为。

对于无符号类型,符号扩展不起作用,因为它们是......,好吧,无符号: - )

答案 1 :(得分:0)

默认情况下,

char已签名 - 这意味着数字从-128到127运行。除此之外的任何数字都不适合。如果您将char更改为unsigned char,则会获得您期望的数字。

答案 2 :(得分:0)

使用memcpy而不是演员

char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int* ptr = (unsigned int*)buff;

这不正确buff未指向int对象或数组,因此未定义强制转换(unsigned int*)buff

buff重新解释为unsigned int的安全方式是memcpy

char buff[4] = {0x17, 0x89, 0x39, 0x40};
unsigned int ui;
assert (sizeof ui == sizeof buff);
memcpy (buff, &ui, sizeof ui);

使用memcpy时,您无法确定您复制的位代表是否对目标类型有效。

一种可移植但退化的方法是检查表示是否与现有对象匹配(注意,以下是愚蠢的代码):

char *null_ptr = 0;
char null_bytes[sizeof null_ptr] = {0};
if (memcmp (null_ptr, null_bytes, sizeof null_bytes)==0) {
    char *ptr2;
    memcpy (null_bytes, ptr2, sizeof null_bytes);
    assert (ptr2 == 0);
}

此代码使用memcpy并具有完全定义的行为(即使无用)。

的行为
int *ptr3 = (int*)null_bytes;

未定义,因为null_bytes不是intunsigned int的地址。