使用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条裤衩的水平是没有办法解决了。高手们。拉兄弟一把吧~~~

解决方案 »

  1.   

    yycec(羊羊羊) 你的回答太令大家失望了,这样的答案楼主会不知道!!
    我尝试了一下,我没有装VC6.0只有.NET,前两个和楼主说的一样,最后一种没有报错,但是打印出的是
    0.000000
    123强烈关注中,期待编译器高手出现!!!!
      

  2.   

    也许在vc中通不过,在别的c中就可以了.
      

  3.   

    这段代码摘自Microsoft SDK:
    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……-_-#
    楼主如果有兴趣就留下邮箱,我把这个文件发给你,呵呵,我是读不懂它。
      

  4.   

    void main()
    {
        printf("%f\n",5);
        printf("123");
    }
    /////////////////////////////////////////////
    5 占2字节, 5.0 占 4 字节 ,你 把 5改成 5.0 就正常了
      

  5.   

    To titilima(李马)(titilima.yeah.net) :
    根据我的跟踪,调用次序是这样的:
    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)
    我继续分析。
      

  6.   

    To fycom200(恋上C++) :
    不可能吧,我试过了,4个字节。
      

  7.   

    5.0就成了double了,虽然表面上数值一样,但double和int在内存中的存储完全不同。自然不会出错了。
      

  8.   

    TO FreeSeagull(孤海闲鸥) :
      哦,忘了,我是在DEV-C++中调试的,在VC中的确5是4字节,5.0是8字节.我还以为是TC2.0了
      

  9.   

    我不太懂,我认为在调用时 5 默认成 int 型(4字节) 但在这个调用中并没发生强制转换,所以用二进制展开比较一下应该可以找到原因的
    00000000 00000000 00000000 00000101  (5)
      

  10.   

    主要是va_list造成的,这种变参在C是以format开头连续分配的缓冲区,所以变参的C函数不能以PASCAL
    调用.在这边就已经应该出错了
      

  11.   

    关注+学习
    printf("%f",5);这样好象没问题啊,
      

  12.   

    http://blog.csdn.net/whs1980/archive/2004/11/13/180255.aspx
    看看这篇文章,也许对你有用。
      

  13.   

    printf("%f\n",5);
      int i = 0  ;
    也不会错。我想是不是它跑过头,到了其他变量的地址空间中去了,如果那个位置没有其他变量在就错了啊
      

  14.   

    不好意思写错了
    printf("%f\n",5);
    float i = 0  ;
    才不会错
      

  15.   

    看楼主说得那么玄妙,不禁起了好奇之心!
    我改了下代码,如下: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,所以……我想大家也都明白了!
      

  16.   

    附带说一下,如果第一次编译程序中只有printf("%f\n", 5);,程序会出错,但是用了printf("%f\n", (float) 5);再编译(此时不会错),但是如果注释掉该行之后,由于VC的优化,再编译运行也是没有问题的,但只要"rebuild all",错误会再次出现!
      

  17.   

    把list文件生成出来,直接看汇编码。有时候可能是编译器的问题。
      

  18.   

    楼主和海天一色等才是真正的programmer。
    像我这样的人,充其量coder而已!
    佩服!
      

  19.   

    To roger_ding(海天一色):
    果然是这样!呵呵~
    北京的朋友吗?我请客!
      

  20.   

    想想程序运行堆栈就知道了。
    对于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",类似与缓冲区溢出-_-!!
      

  21.   

    To CounterHack(反击黑客):
    In Windows 2k: sizeof(int) = sizeof(float) = 4
      

  22.   

    to  FreeSeagull(孤海闲鸥)
    呵呵,可惜我不在北京的,谢谢好意了!
      

  23.   

    好像以前在坛子里看过一片文章说,如果整个程序都没有直接声明过float类型,那么即使用到了%f格式,也没有真正启用浮点运算,被优化掉了。但只要这个程序中某处声明过float类型的数据,浮点运算就真正生效了。看起来楼主的问题与此相同。
      

  24.   

    printf("%f\n",5); 中 %f只是个字符串而已,跟编译器根本就没任何关系,这个调用中 5 被默认成 int 型(4字节),而printf函数在实现的时候根据%f的指示又把传递过去的数据当成 float 来处理的,但这个处理并不是强制转换.而是多访问了4个字节而已,比如5被传到下面这段内存的开始处,那么printf函数在访问时把它当成 float 处理(8字节),也就是多访问了4字节(1字节)(2字节)(3字节)(4字节)(5字节)(6字节)(7字节)(8字节)以上是我的个人看法,望高手不吝赐教!