printf格式化输出%x时的分析

使用printf(“%x”,…);可以输出指定参数的16进制形式,但是在实际的使用中,参数不一定都是32位的整数,有可能是16位的short,8位的char。如果使用printf %x 输出short和char会是什么结果呢? 
为此,在VS2015编写简单代码如下:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int l;
    short s;
    char c;
    l = 0xdeadbeef;
    s = l;
    c = l;
    printf("%x\n", l);
    printf("%x\n", s);
    printf("%x\n", c);
    system("pause");
    return 0;
}

分析
代码比较简单,首先定义了3个变量,然后对三个变量进行赋值,在赋值的过程中会发生宽度溢出。
s=l 将32位的整数放入16位的short,那么s的值只是l的低16位,即s=0xbeef;
c=l 将32位的整数放入8位的char,那么c的值应该只是l的低8位,即s=0xef;
因此预测输出:
deadbeef
beef
ef

我们运行一下代码看分析是否正确: 
运行结果: 
这里写图片描述 
与我们分析的还是有些差别,差别在于第二个与第三个输出多出了好多ff. 
那么这些ff是怎么来的呢? 
我们在printf(“%x”,s);加断点看反汇编的结果:

0017140E  movsx       eax,word ptr [s]  
00171412  mov         esi,esp  
00171414  push        eax  
00171415  push        175858h  
0017141A  call        dword ptr ds:[179118h] 

movsx eax,word ptr [s];后,我们看看eax的值: 
EAX = FFFFBEEF 
看来参数压栈之前,参数的值就已经是FFFFBEEF了,也难怪会打印出FFFFBEEF,而不是打印BEEF. 
那么为什么经过 movsx eax,word ptr [s]后 eax的高16位会变化为ffff? 
这需要从movsx说起了。 
MOVSX 指令:带符号扩展传送指令,将第二个操作数当作有符号类型取其符号位进行扩展。 
movsx eax,word ptr [s] 
word ptr [s]的值为0xbeef,二进制为1011 1110 1110 1111 
最高位(符号位)为1,于是扩展的时候会将eax的高16位全部扩展为1.于是就输出了如上结果。 
那么如果s的最高位为0呢?会如何扩展呢?那高位就应该扩展0.我们对代码稍加修加。

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int l;
    short s;
    char c;
    l = 0xdead0eef;
    s = l;
    c = l;
    printf("%x\n", l);
    printf("%x\n", s);
    printf("%x\n", c);
    system("pause");
    return 0;
}

我们将l的deadbeef改成dead0eef,为的是让s的最高位为0。 
看输出结果: 
这里写图片描述 
可以看到因为s的最高位为0,于是输出的时候没有 了ffff出现。 
但是c的最高位为1(因为c==1110 1111),eax的高位全部扩展为1了,于是第三个输出还是扩展的FFFFFFEF。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值