2

我正在尝试了解以下代码的输出:http: //phrack.org/issues/60/10.html

在这里引用它以供参考:

#include <stdio.h>

int main(void){
        int l;
        short s;
        char c;

        l = 0xdeadbeef;
        s = l;
        c = l;

        printf("l = 0x%x (%d bits)\n", l, sizeof(l) * 8);
        printf("s = 0x%x (%d bits)\n", s, sizeof(s) * 8);
        printf("c = 0x%x (%d bits)\n", c, sizeof(c) * 8);

        return 0;
}

我在我的机器上得到的输出是:-

l = 0xdeadbeef (32 bits)
s = 0xffffbeef (16 bits)
c = 0xffffffef (8 bits)

这是我的理解:-

赋值 s=l, c=l 将导致 s 和 c 被提升为整数,它们将分别具有 l 的最后 16 位 (0xbeef) 和最后 8 位 (0xef)。

Printf 尝试将上述每个值(l、s 和 c)解释为无符号整数(因为 %x 作为格式说明符传递)。从输出中我看到符号扩展已经发生。我的疑问是,既然 %x 代表 unsigned int,为什么在打印 s 和 c 时会发生符号扩展?s 的输出不应该是 0x0000beef 而 c 的输出不应该是 0x000000ef 吗?

4

2 回答 2

2

为什么在打印 s 和 c 时发生符号扩展

让我们看看下面的代码:

unsigned char ucr8bit; /* Range is 0 to 255 on my machine */
signed char cr8bit; /* Range is -128 to 127 on my machine */
int i32bit;
cr8bit = MINUS_100;  /* (char)(-100) or 0x9C */
i32bit = cr8bit;     /* i32 bit is -100 or 0xFFFFFF9C */

如您所见,尽管数字-100相同,但它的表示不仅仅是0在更广泛的字符中添加 s,而是可能signed2s 补码系统和1s 补码系统中添加类型的 MSB 或符号位。

在您的示例中,您正在尝试打印sc作为更宽的类型,从而获得符号位复制。


此外,您的代码包含许多未定义和未指定行为的来源,因此可能会在不同的编译器上给出不同的输出。(例如,您应该使用signed char而不是charaschar可能unsigned char在某些实现和signed char其他一些实现上表现得那样)

l = 0xdeadbeef; /* Initializing l from an unsigned
                   if sizeof l is 32 bit UB as l is signed */
s = l;  /* Initializing with an undefined value. Moreover
           implicit conversion wider to narrower type */
printf("l = 0x%x (%d bits)\n", l, sizeof(l) * 8);  /* Using %x
               to print signed number and %d to print size_t */
于 2015-01-19T06:11:46.477 回答
1

您正在使用 32 位有符号整数。这意味着只有 31 位可用于正数。0xdeadbeef 使用 32 位。因此,将其分配给 32 位有符号整数使其成为负数。

当使用无符号转换说明符 %x 显示时,它看起来就像是负数(带有符号扩展名)。

将其复制为 short 或 char 时,保留其为负数的属性。

要进一步显示这一点,请尝试设置:

l = 0xef;

现在的输出是:

l = 0xef (32 bits)
s = 0xef (16 bits)
c = 0xffffffef (8 bits)

0xef 使用 8 位,当放入 32 位或 16 位变量时为正数。当您将 8 位数字放入带符号的 8 位变量 (char) 时,您将创建一个负数。

要查看负数的保留情况,请尝试相反的操作:

c = 0xef;
s = c;
l = c;

输出是:

l = 0xffffffef (32 bits)
s = 0xffffffef (16 bits)
c = 0xffffffef (8 bits)
于 2015-02-27T00:10:19.550 回答