0

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

#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

4

3 回答 3

4

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

您可以通过显式使用来修复它,unsigned char因为至少在 C 中,char有符号或无符号是特定于实现的。来自C11 6.2.5 Types /15

实现应将 char 定义为与有符号字符或无符号字符具有相同的范围、表示和行为。

符号扩展不会对无符号类型起作用,因为它们是……嗯,无符号 :-)

于 2013-07-03T02:36:56.533 回答
0

默认情况下,char 是有符号的 - 这意味着数字从 -128 运行到 127。任何超出此范围的数字都不适合。如果您更改charunsigned char,您将获得您期望的数字。

于 2013-07-03T02:36:52.650 回答
0

不使用memcpy演员表

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

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

buff重新解释为 an的安全方法unsigned intmemcpy

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并具有完全定义的行为(即使无用)。OTOH,的行为

int *ptr3 = (int*)null_bytes;

没有定义,因为null_bytes不是intor的地址unsigned int

于 2013-07-03T02:40:40.277 回答