在短的情况下签名扩展查询

时间:2014-10-15 21:50:47

标签: c

鉴于,

unsigned short y = 0xFFFF;

我打印时

printf("%x", y);

我得到:0xFFFF;

但是当我打印

printf("%x", (signed short)y);

我得到:0xFFFFFFFF

以下整个计划:

#include <stdio.h>
int main() {
    unsigned short y = 0xFFFF;
    unsigned short z = 0x7FFF;

    printf("%x %x\n", y,z);
    printf("%x %x", (signed short)y, (signed short)z);

    return 0;
}

当我们将较低字节数据类型转换为较高字节数据类型时,会发生符号扩展,但是这里我们将签名简短的类型缩短。 在两种情况下,sizeof((有符号短)y)或sizeof((有符号短)z)打印2个字节。如果符号位为0,则为0x7fff的短字节,为2个字节。 非常感谢任何帮助!

2 个答案:

答案 0 :(得分:5)

第一个printf的输出符合预期。第二个printf产生未定义的行为。

在C语言中,当您传递小于int的值作为可变参数时,该值始终隐式转换为类型int。物理传递shortchar可变参数不可能。隐式转换为int是您的&#34;签署扩展名&#34;发生了。

因此,您的printf("%x", y);相当于printf("%x", (int) y);。传递给printf的值为0xFFFF类型的int。从技术上讲,%x格式需要unsigned int参数,但非负int值也可以(除非我缺少一些技术性)。输出为0xFFFF

在第二种情况下也会转换为int。即您的printf("%x", (signed short) y);相当于printf("%x", (int) (signed short) y);0xFFFF(signed short)的转换是由实现定义的,因为0xFFFF显然超出了您平台上signed short的范围。但最有可能产生负值(-1)。转换为int时,它会生成类型int的相同负值(同样,-1表示为0xFFFFFFFF,用于32位int。进一步的行为是未定义的,因为您要为格式说明符int传递负%x值,这需要unsigned int参数。使用%xint值为printf是违法的。

换句话说,正式你的第二个0xFFFFFFFF打印出不可预测的垃圾。但实际上上面解释了{{1}}的来源。

答案 1 :(得分:1)

让我们把它分解成小块:

  

鉴于,

     

unsigned short y = 0xFFFF;

假设最大值为unsigned short的{​​{1}}为2^16-1,那确实是0xFFFF

  

我打印时

     

printf("%x", y);

由于默认参数提升(因为printf()是可变函数),y的值被隐式提升为类型int。如果指定了%x格式,则将其视为unsigned int。假设公共双补码表示和四字节int类型,这意味着当最高有效位设置为零时,intunsigned int的位模式完全相同。

  

但是当我打印

时      

printf("%x", (signed short)y);

您所做的是转换为签名类型,不能代表0xFFFF的值。标准停留的这种转换是实现定义的,因此您可以得到任何结果。在隐式转换为int之后,您显然拥有32位的位图,表示为0xFFFFFFFF