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。
上一篇: C语言学习
下一篇: 2015年第六届蓝桥杯C++B组D题
推荐阅读
-
perl的格式化输出及chomp的重要性分析
-
编写程序: 从键盘上输入一个整数x,判断其奇偶性;当x满足 x%2==0(即x是2的倍数)时,输出x是偶数;反之,输出x是奇数(x为具体的数值)。
-
C/C++格式化输出(printf、fprintf、sprintf、syslog等)的不安全用法
-
printf("%m.nd",x)格式化输出详解
-
java printf的格式化输出
-
分析 snprintf sprintf printf 等 类“printf” 格式化输出函数,由于类型不兼容造成的内存混乱
-
格式化输出函数printf( )的格式控制说明
-
Java中关于日期的printf格式化输出
-
c语言 printf 输出格式控制 %#x 带0x 16进制的输出
-
php printf() 输出格式化的字符串,phpprintf_PHP教程