有符号/无符号int、short和char

有符号/无符号int、short和char,c,printf,integer-promotion,C,Printf,Integer Promotion,我试图理解以下给出的代码的输出: 在此引用以供参考: #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 =

我试图理解以下给出的代码的输出:

在此引用以供参考:

#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;
}
以下是我的理解:-

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

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

为什么在打印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,还可能在system和system中预加有符号的
类型的MSB或符号位

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


此外,您的代码还包含许多未定义和未指定行为的源,因此可能在不同的编译器上提供不同的输出。 (例如,您应该使用
signed char
而不是
char
,因为
char
在某些实现中可能表现为
unsigned char
,在某些其他实现中可能表现为
signed char


您使用的是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)

标志延伸发生在推送过程中,而不是打印过程中。您的任务是由实现定义的。如果一个值对于一个有符号的目标类型是不可表示的,那么实现将接管它。不要依赖于观察到的行为(尽管位截断确实是我见过的最常见的行为)。
printf
是一个可变函数,这意味着调用函数时,
short
char
类型的参数被提升为
int
sizeof
返回
size\u t
,若要打印必须使用的
size\u t
,并且一个字节并不总是有8位,请改用
char\u BIT
“作业
s=l
c=l
将导致
s
c
被提升为
int
”-更像“将导致
l
被截断为
short
char
“。如果
short
char
始终升级为
int
,则
printf(“%x”,someShortValue))
在各个方面都必须与printf(“%x”,(int)someShortValue)等效,已定义,对吗?@immibis这两个都会导致未定义的行为
%x
只能与
无符号int
一起使用。将
%x
int
的非负值一起使用;或者更小的值被提升为非负值
int
,这在技术上是未定义的行为,但大多数人似乎认为该标准在该领域存在缺陷,实际上,我们将其视为它确实允许这样做。
c = 0xef;
s = c;
l = c;
l = 0xffffffef (32 bits)
s = 0xffffffef (16 bits)
c = 0xffffffef (8 bits)