使用VC++ 6调试如下程序:#include <stdio.h>
#include <stdlib.h>void main()
{
printf("%f\n",5);
}编译通过,但运行出错。原因我猜想是因为浮点数中的31-23位这八个指数位不能为0。如果把程序改成这样就不会出错:void main()
{
printf("%f\n",5);
printf("%f\n",(float)5);
}当场昏倒!醒来后强人悲愤,继续修改,把main函数修改成这样:
void main()
{
printf("%f\n",5);
printf("123");
}错误又出现了!!!好奇怪啊! 看来以兄弟我这5条裤衩的水平是没有办法解决了。高手们。拉兄弟一把吧~~~
#include <stdlib.h>void main()
{
printf("%f\n",5);
}编译通过,但运行出错。原因我猜想是因为浮点数中的31-23位这八个指数位不能为0。如果把程序改成这样就不会出错:void main()
{
printf("%f\n",5);
printf("%f\n",(float)5);
}当场昏倒!醒来后强人悲愤,继续修改,把main函数修改成这样:
void main()
{
printf("%f\n",5);
printf("123");
}错误又出现了!!!好奇怪啊! 看来以兄弟我这5条裤衩的水平是没有办法解决了。高手们。拉兄弟一把吧~~~
我尝试了一下,我没有装VC6.0只有.NET,前两个和楼主说的一样,最后一种没有报错,但是打印出的是
0.000000
123强烈关注中,期待编译器高手出现!!!!
int __cdecl printf (
const char *format,
...
)
/*
* stdout 'PRINT', 'F'ormatted
*/
{
va_list arglist;
int buffing;
int retval; va_start(arglist, format); _ASSERTE(format != NULL);#ifdef _MT
_lock_str2(1, stdout);
__try {
#endif /* _MT */ buffing = _stbuf(stdout); retval = _output(stdout,format,arglist); _ftbuf(buffing, stdout);#ifdef _MT
}
__finally {
_unlock_str2(1, stdout);
}
#endif /* _MT */ return(retval);
}
从中可以发现,printf中是调用了一个_output函数来完成的。
在打开output.c文件之后,我发现这个函数中对%f(%e/%g)和%d的处理是分开了两个case的情况。但没有办法,这个文件有46KB……-_-#
楼主如果有兴趣就留下邮箱,我把这个文件发给你,呵呵,我是读不懂它。
{
printf("%f\n",5);
printf("123");
}
/////////////////////////////////////////////
5 占2字节, 5.0 占 4 字节 ,你 把 5改成 5.0 就正常了
根据我的跟踪,调用次序是这样的:
main.cpp : printf("%f\n",5);
printf.c : retval = _output(stdout,format,arglist);
output.c : _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
其中:#define _cfltcvt(a,b,c,d,e) (*((PF0)_cfltcvt_tab[0]))(a,b,c,d,e)
就是从这里开始出现错误。然后是:
crtofp: : _fptrap();
crto.c : _amsg_exit(_RT_FLOAT);
crtomsg.c: _FF_MSGBANNER(); _NMSG_WRITE(_RT_BANNER);
_output()函数中,对于%e,%f,%g的处理是一个入口。
我又分析了一下,可能问题就出来这一句上:_cfltcvt(&tmp,text.sz, (char)ch, precision, capexp)
我继续分析。
不可能吧,我试过了,4个字节。
哦,忘了,我是在DEV-C++中调试的,在VC中的确5是4字节,5.0是8字节.我还以为是TC2.0了
00000000 00000000 00000000 00000101 (5)
调用.在这边就已经应该出错了
printf("%f",5);这样好象没问题啊,
看看这篇文章,也许对你有用。
int i = 0 ;
也不会错。我想是不是它跑过头,到了其他变量的地址空间中去了,如果那个位置没有其他变量在就错了啊
printf("%f\n",5);
float i = 0 ;
才不会错
我改了下代码,如下:void test()
{
printf("%f\n", (float) 5);
}int main(int argc, char* argv[])
{
printf("%f\n", 5);
return 0;
}发现仍然不会出错,即使test()没有被调用,所以我猜可能是程序某些地方根据编译结果进行了优化,于是在main入口处断,根据call stack list进入void mainCRTStartup(...),该函数有处地方
_cinit(); /* do C data initialize */
跟进瞧瞧,void __cdecl _cinit (
void
)
{
/*
* initialize floating point package, if present
*/
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
/*
* MIPS compiler doesn't emit external reference to _fltused. Therefore,
* must always force in the floating point initialization.
*/
_fpmath();
#else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
if ( _FPinit != NULL )
(*_FPinit)();
#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */可以发现_FPinit,此乃重点,它的作用是初始化协处理器FPU(即浮点运算器),如果程序中只有printf("%f\n", 5); _FPinit此时为NULL,所以没有初始化FPU,程序无法进行浮点运算,即出错,当用了printf("%f\n", (float) 5);后,_FPinit不为空,(*_FPinit)();就会被调用!也即关键所在!附:同理,float i = 0;既然定义了float,所以……我想大家也都明白了!
像我这样的人,充其量coder而已!
佩服!
果然是这样!呵呵~
北京的朋友吗?我请客!
对于printf函数,根据格式字符串"%f\n",函数认为你将压sizeof(float)字节入栈,而事实上,你写成 printf("%f\n",5);时,因为5默认是int,即压sizeof(int)字节入栈,导致printf函数寻址出错!后续语句printf(%f\n",(float)5)时,程序可以运行是因为(float)5这个变量(注:对于printf函数来说(float)5是一个寻址动作),是有效的地址空间:)类似与如下:
char p1[2] = {"12"};
char p2[] = {"34"};
AfxMessageBox(p1);//弹出"1234",类似与缓冲区溢出-_-!!
In Windows 2k: sizeof(int) = sizeof(float) = 4
呵呵,可惜我不在北京的,谢谢好意了!