有符号/无符号的int,short和char

时间:2015-01-19 05:38:00

标签: c printf integer-promotion

我正在尝试理解在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吗?

2 个答案:

答案 0 :(得分: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更广泛的字符,而是可能在signed的MSB或符号位之前。输入2s complement系统和1s complement系统。

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


此外,您的代码包含许多未定义和未指定行为的来源,因此可能在不同的编译器上提供不同的输出。 (例如,您应该使用signed char代替char,因为char在某些实现上可能表现为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 */

答案 1 :(得分: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)