printf输出float和double类型数据的问题

lvjing_CSDN 2012-12-18 06:45:57
以前都一直以为printf输出double类型使用的是%lf,今天才发现输出float和double使用的都是%f。这让我很是迷惑。因为printf是变参函数,参数的入栈和出栈都是由被调用者完成。printf识别各个参数完全是通过输出格式字符串中获取要输出的参数的类型。float和double分别占用4和8个字节的空间,当printf看到%f的时候如何知道这个数据是几个字节呢?难道float类型在入栈的时候也是自动按照double来如栈吗?
如果各位有知道其中原因的,还望不吝赐教。
...全文
5963 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
纹枰老妖 2014-08-31
  • 打赏
  • 举报
回复
在我的机器上,任何浮点数常量,传递给函数时压栈,都是当做double类型存储,即 这种浮点常量参数所占用的空间比int型要大,也比float要大
BeanJoy 2012-12-19
  • 打赏
  • 举报
回复
引用 22 楼 supermegaboy 的回复:
在论坛里了解一下赵大师的过去就明白了。
没那个必要,来坛子里,就是为了学习计算机方面知识、帮别人解决问题。 能让我学到更多、能解决我和其他网友遇到的问题就足矣。
飞天御剑流 2012-12-19
  • 打赏
  • 举报
回复
在论坛里了解一下赵大师的过去就明白了。
BeanJoy 2012-12-19
  • 打赏
  • 举报
回复
引用 20 楼 supermegaboy 的回复:
噢,刚刚才发现赵大师原来还是马甲大师、自导自演大师、伪装大师………哎呀,不出奇啊,不就是一个没有道德底线的奇葩么……
何出此话?
gladstonejay 2012-12-19
  • 打赏
  • 举报
回复
学习了 不错
飞天御剑流 2012-12-19
  • 打赏
  • 举报
回复
噢,刚刚才发现赵大师原来还是马甲大师、自导自演大师、伪装大师………哎呀,不出奇啊,不就是一个没有道德底线的奇葩么……
赵4老师 2012-12-19
  • 打赏
  • 举报
回复
引用 18 楼 BeanJoy 的回复:
引用 17 楼 zhao4zhong1 的回复:引用 1 楼 BeanJoy 的回复:等待赵老师! 先 http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express 点开Visual C++ 2010 Express下面的语言选‘简体中文’,再点立即安装 再参考C:\Program Fil…… 其他我是等待你从汇编角度去分析下的。 11楼我已给出了printf实现的主要代码,并做了分析。
你的是VC6,我的是更高版本而已。 有C源代码的情况下,如果阅读或单步相关C语句后已经没有疑问了,就没必要再在单步时按Alt+8看对应汇编指令了。
BeanJoy 2012-12-19
  • 打赏
  • 举报
回复
引用 17 楼 zhao4zhong1 的回复:
引用 1 楼 BeanJoy 的回复:等待赵老师! 先 http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express 点开Visual C++ 2010 Express下面的语言选‘简体中文’,再点立即安装 再参考C:\Program Files\Microsoft Visual Stud……
其他我是等待你从汇编角度去分析下的。 11楼我已给出了printf实现的主要代码,并做了分析。
赵4老师 2012-12-19
  • 打赏
  • 举报
回复
引用 1 楼 BeanJoy 的回复:
等待赵老师!
http://www.microsoft.com/visualstudio/chs/downloads#d-2010-express 点开Visual C++ 2010 Express下面的语言选‘简体中文’,再点立即安装 再参考C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\output.c
shirui8653719 2012-12-19
  • 打赏
  • 举报
回复
学习了啊。
nevermorewish 2012-12-19
  • 打赏
  • 举报
回复
引用 11 楼 BeanJoy 的回复:
引用/* +++++++++++++++++++++++++++++++++++++++++++ Because of parameter passing conventions in C: use mode=int for char, and short types use mode=double for float types ……
++
nice_cxf 2012-12-19
  • 打赏
  • 举报
回复
float是先转的double然后入的栈,很多贴说过这个的。。。
didijiji 2012-12-19
  • 打赏
  • 举报
回复
float隐式转换成double类型之后,再入栈。
AnYidan 2012-12-19
  • 打赏
  • 举报
回复
First, if either operand is long double, the other is converted to long double. ?Otherwise, if either operand is double, the other is converted to double. ?Otherwise, if either operand is float, the other is converted to float. ?Otherwise, the integral promotions are performed on both operands; then, if either operand is unsigned long int, the other is converted to unsigned long int. 175 ?Otherwise, if one operand is long int and the other is unsigned int, the effect depends on whether a long int can represent all values of an unsigned int; if so, the unsigned int operand is converted to long int; if not, both are converted to unsigned long int. ?Otherwise, if one operand is long int, the other is converted to long int. ?Otherwise, if either operand is unsigned int, the other is converted to unsigned int. ?Otherwise, both operands have type int 好像从 c89 开始,如果 没有 operands 是 double, 则 float 不用转换为 double, 为何 printf()如此奇怪?
赵4老师 2012-12-19
  • 打赏
  • 举报
回复
其实supermegaboy兄是标准控,本人是实证控而已。 尺有所短,寸有所长。 矛盾的统一,警匪一家。
赵4老师 2012-12-19
  • 打赏
  • 举报
回复
引用 20 楼 supermegaboy 的回复:
噢,刚刚才发现赵大师原来还是马甲大师、自导自演大师、伪装大师………哎呀,不出奇啊,不就是一个没有道德底线的奇葩么……
啥叫“道德底线”?请举例说明。
BeanJoy 2012-12-18
  • 打赏
  • 举报
回复
引用
/* +++++++++++++++++++++++++++++++++++++++++++ Because of parameter passing conventions in C: use mode=int for char, and short types use mode=double for float types use a pointer for array types +++++++++++++++++++++++++++++++++++++++++++ */
VC98\Include\STDARG.h对于系列变参宏的说明。 其际上,也确实如此,将float作为参数传递给变参函数,编译时,会自动将float的值转换为double,然后压入栈。

    ...
    while ((ch = *format++) != _T('\0') && charsout >= 0) {
        chclass = find_char_class(ch);  /* find character class */
        state = find_next_state(chclass, state); /* find next state */

        /* execute code for each state */
        switch (state) {

	...
        case ST_SIZE:
            /* just read a size specifier, set the flags based on it */
            switch (ch) {
#if !LONG_IS_INT || !defined (_UNICODE)
            case _T('l'):
                flags |= FL_LONG;   /* 'l' => long int or wchar_t */
                break;
#endif  /* !LONG_IS_INT || !defined (_UNICODE) */
	...
	case ST_TYPE:
            switch (ch) {
            ...
            case _T('E'):
            case _T('G'):
                capexp = 1;                 /* capitalize exponent */
                ch += _T('a') - _T('A');    /* convert format char to lower */
                /* DROP THROUGH */
            case _T('e'):
            case _T('f'):
            case _T('g'): {
                /* floating point conversion -- we call cfltcvt routines */
                /* to do the work for us.                                */
                flags |= FL_SIGNED;         /* floating point is signed conversion */

#if !LONGDOUBLE_IS_DOUBLE
                /* do the conversion */
                if (flags & FL_LONGDOUBLE) {
                    LONGDOUBLE tmp;
                    tmp=va_arg(argptr, LONGDOUBLE);
                    /* Note: assumes ch is in ASCII range */
                    _cldcvt(&tmp, text.sz, (char)ch, precision, capexp);
                } else
#endif  /* !LONGDOUBLE_IS_DOUBLE */
                {
                    DOUBLE tmp;
                    tmp=va_arg(argptr, DOUBLE);
                    /* Note: assumes ch is in ASCII range */
                    _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
                }
		...
            }
            break;
以上是printf实现的主要代码,其中须要说明的几个宏: 1.LONG_IS_INT:printf实现代码中始终定义为1; 2.LONGDOUBLE_IS_DOUBLE:在定义了_WIN32宏的情况下,被定义为1;在定义了_M_MPPC情况下,被定义为1;在定义了_M_M68K情况下,被定义为0;_WIN32、_M_MPPC与_M_M68K为Microsoft C++预先定义的,编译WIN32程序中是定义的_WIN32,因此LONGDOUBLE_IS_DOUBLE被定义为1; 3.DOUBLE:被定义为double。 这样,上面的代码就好看了,主要的是:

{
                    DOUBLE tmp;
                    tmp=va_arg(argptr, DOUBLE);
                    /* Note: assumes ch is in ASCII range */
                    _cfltcvt(&tmp,text.sz, (char)ch, precision, capexp);
}
因此"%f"也是按double读取的8字节,若实参为float,编译时会自动转换为double的。
飞天御剑流 2012-12-18
  • 打赏
  • 举报
回复
引用 7 楼 lvjing_CSDN 的回复:
引用 5 楼 wxycwfj 的回复:是因为使用了自动向上类型转换 可是自动类型提升是在运算的时候进行的啊,这里没有什么运算,只是把数据压栈。
5楼说的基本没错,只不过不是类型提升,而是usual arithmetic conversions。 可变参数函数一般不进行类型检查,但printf的float是个例外,float在入栈前先被转换为double,这是为了兼容K&R C的做法。
lvjing_CSDN 2012-12-18
  • 打赏
  • 举报
回复
引用 8 楼 gumh 的回复:
和printf實現相關, ms應該是統一將他們當作double處理
应该不是吧,好像标准也是这么讲的。
prajna 2012-12-18
  • 打赏
  • 举报
回复
和printf實現相關, ms應該是統一將他們當作double處理
加载更多回复(7)

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧