一段代码引起的思考-------printf
2012-03-08 17:39
204 查看
看一小段代码:
#include <stdio.h>
int main()
{
inta =5;
printf("%f\n" a);
return0;
}
在vc6.0和gcc中结果都是0.000000,为什么呢?
这得从int和float的转换说起,我们知道int是4 byte(32位),float也是4 byte,但是printf函数在将参数以单精度浮点数打印出来时,都是默认转换为双精度浮点数,也就是在在printf函数中,参数a是以32位入栈,但是打印取出时,却是按双精度取出64位,其中int的32位作为新的64位的低32位,高32位一般都为0。
在gdb中对程序进行反汇编:
ps:gcc中一般都有gdb,进入gcc,使用命令gcc –g test.c –o test,然后输入gdb test就可以进入gdb查看反汇编了。在gdb中,汇编指令格式默认是att的,使用命令set disassembly-flavor intel可以将反汇编格式设置成intel的,我将gdb中的汇编格式设置为Intel的,进入gdb后可以设置断点,可以单步执行,还可以将某个函数的汇编打印出来,从汇编中可以看到int确实是以32位入栈的。
ps:浮点数的表示方法
s为标志位,为1则浮点数为负,为0浮点数为正,exponent为幂位,后面的mantissa为有效位
下面再来看一个例子:
#include <stdio.h>
int main()
{
__int64 b;
b= 0x404B800000000000;
int a ;
a= 55;
printf("%f\n%f\n%f\n",a,b,);
printf("\n%f\n%f\n%f\n",b,a,);
return0;
}
这里说明一下C语言里面参数的入栈和出栈顺序,C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反,如上面第一个printf函数,入栈顺序为b,a,出栈顺序为a、b,a为我定义的一个64位的int变量,为了更好的说明结果,我将55.0的浮点数的64位16进制表示赋给了b,在gcc中运行结果为:
0.000000
0.000000
55.000000
0.000000
在第一个printf中,数据一这样的顺序入栈:0x40B80000、0x0、0x37,出栈后变为0x0000000000000037、0x........40B80000,........一般为0所以结果就为0.000000、0.000000,(有时最后一个可能是乱码)。
在这中间我也有很多不明白的地方,比如反汇编中,我找不到参数在printf中是怎么输出的,还有堆和栈的概念也不是很清晰,这次让我认识到自己的基础很不扎实,唉,小小叹息一下。
programming on the way
#include <stdio.h>
int main()
{
inta =5;
printf("%f\n" a);
return0;
}
在vc6.0和gcc中结果都是0.000000,为什么呢?
这得从int和float的转换说起,我们知道int是4 byte(32位),float也是4 byte,但是printf函数在将参数以单精度浮点数打印出来时,都是默认转换为双精度浮点数,也就是在在printf函数中,参数a是以32位入栈,但是打印取出时,却是按双精度取出64位,其中int的32位作为新的64位的低32位,高32位一般都为0。
在gdb中对程序进行反汇编:
ps:gcc中一般都有gdb,进入gcc,使用命令gcc –g test.c –o test,然后输入gdb test就可以进入gdb查看反汇编了。在gdb中,汇编指令格式默认是att的,使用命令set disassembly-flavor intel可以将反汇编格式设置成intel的,我将gdb中的汇编格式设置为Intel的,进入gdb后可以设置断点,可以单步执行,还可以将某个函数的汇编打印出来,从汇编中可以看到int确实是以32位入栈的。
ps:浮点数的表示方法
s为标志位,为1则浮点数为负,为0浮点数为正,exponent为幂位,后面的mantissa为有效位
下面再来看一个例子:
#include <stdio.h>
int main()
{
__int64 b;
b= 0x404B800000000000;
int a ;
a= 55;
printf("%f\n%f\n%f\n",a,b,);
printf("\n%f\n%f\n%f\n",b,a,);
return0;
}
这里说明一下C语言里面参数的入栈和出栈顺序,C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反,如上面第一个printf函数,入栈顺序为b,a,出栈顺序为a、b,a为我定义的一个64位的int变量,为了更好的说明结果,我将55.0的浮点数的64位16进制表示赋给了b,在gcc中运行结果为:
0.000000
0.000000
55.000000
0.000000
在第一个printf中,数据一这样的顺序入栈:0x40B80000、0x0、0x37,出栈后变为0x0000000000000037、0x........40B80000,........一般为0所以结果就为0.000000、0.000000,(有时最后一个可能是乱码)。
在这中间我也有很多不明白的地方,比如反汇编中,我找不到参数在printf中是怎么输出的,还有堆和栈的概念也不是很清晰,这次让我认识到自己的基础很不扎实,唉,小小叹息一下。
programming on the way
相关文章推荐
- 一段旧代码,引起的关于OO中一个问题的思考
- 一段简单的C代码引起的思考-局部字符串变量传参
- 一段代码引起的思考(变量占用字节数及指针)
- 一段代码引起的思考-----编译器
- 一段代码引起的对C++构造函数、析构函数,复制构造函数,运算符重载的深度理解
- javascript 一段代码引发的思考第1/2页
- 为什么Thread.stop会过期?一段引起同步异常问题的代码样例
- 一段代码引发的思考
- 由闭包引起的对javascript代码可维护性的思考
- 一段Spring代码引起的调用绑定总结
- 由闭包引起的对javascript代码可维护性的思考
- 一段奇葩Javascript代码引发的思考
- 【C】由printf("%d\t%d\t%d\n",a,a+=(a++),a);引起的思考
- 对Hadoop中一段将字节码数组转换为Integer的代码的思考
- 一段小代码的思考
- 由一段JS代码引发的思考
- 一段代码引发的思考-----(类及操作符重载,数组相加)
- 由闭包引起的对javascript代码可维护性的思考
- 看到一段代码,思考Element
- 一段代码既说明printf的入栈顺序是从右想做的,又说明inet_ntoa返回值是放在一个静态区域的,连续执行会覆盖