社区
C语言
帖子详情
printf的问题,非常奇怪,百思不得其解
widowss
2005-12-29 11:21:11
#include <stdio.h>
main()
{
int i=5;
printf("%d",5.0);
printf("%d",i);
printf("%f",5.0);
}
为什么输出结果是0,5.00000。第一个0是怎么得来得,尝试自己写一个类似printf的程序,没有成功,谁能解释一下啊。
...全文
574
18
打赏
收藏
printf的问题,非常奇怪,百思不得其解
#include main() { int i=5; printf("%d",5.0); printf("%d",i); printf("%f",5.0); } 为什么输出结果是0,5.00000。第一个0是怎么得来得,尝试自己写一个类似printf的程序,没有成功,谁能解释一下啊。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
18 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
plane10598
2005-12-31
打赏
举报
回复
没试过!也很奇怪
Renkey
2005-12-30
打赏
举报
回复
期待,学习下。
Grubby_c
2005-12-30
打赏
举报
回复
关注 cky41(有点魄力)
关注高手
bombwang
2005-12-30
打赏
举报
回复
learning
megaboy
2005-12-29
打赏
举报
回复
printf由于是可变参数函数,它是不自动进行类型转换的,而是根据格式说明符的说明去读取参数的内容,printf("%d", 5.0)这样是把5.0这个浮点数的浮点内存映象当作整数来读取,当然不是你所预期的结果。
goodluckyxl
2005-12-29
打赏
举报
回复
0040102F push 40140000h
00401034 push 0 //是这样的push了0
00401036 push offset string "%d" (00424020)
0040103B call printf (004010a0)
00401040 add esp,0Ch
改成5就push 5 了
goodluckyxl
2005-12-29
打赏
举报
回复
不会吧 有这事
afei_xyd
2005-12-29
打赏
举报
回复
这个函数是可变参数的函数,其实现不看后面参数有多少个的,只看第一个参数,根据数据格式来输出字符串,当后面的数据类型不一致是不进行数据类型转换的,可能是默认值吧。关于自己实现printf()函数,我见过现在找不到了。可能是标准c 里吧,你自己找找
sankt
2005-12-29
打赏
举报
回复
学习
xombat
2005-12-29
打赏
举报
回复
说的很清楚了
widowss
2005-12-29
打赏
举报
回复
同期待
iwantfat
2005-12-29
打赏
举报
回复
关注
kangji
2005-12-29
打赏
举报
回复
有意思
cky41
2005-12-29
打赏
举报
回复
这个问题比较复杂
先说我是在GNU/Linux平台上测试的。
printf ("%d\n", 5.0)
编译器看到带有小数点的十进制数,那么会将其默认为double类型(而不是float),double类型在一般的机子里都占有8个字节(64位)。但是%d对应int类型,int类型在一般的机子里占有4个字节(32位,也就是long),所以%d只读传给printf的低4字节的值,而这4字节刚好是0,所以printf ("%d\n", 5.0)打印出0。前面goodluckyxl用汇编表示的更清楚。
至于为什么这低4字节刚好是0,这跟浮点数在计算机中的实际存储有关。int 5在内存中就存为0x00000005,但是float 5或者double 5在内存中决不是这么简单的数,它会高字节低字节的存不同的信息,好像是指数尾数之类的,关于这部分我就不清楚了。
所以如果你这样
printf ("%d\n", 5.1),那么我相信低4字节决不是0,这回一定能打印出非0整数。
或者这样
printf ("%lld", 5.0),%lld会转换8字节的值为整数,所以打印出的值一定不是0,但因为上面说得浮点数的存储不同于简单的整数,所以打印出的数可能很怪,一般都很大。
上面这一部分应该能解决楼主的问题了。
下面的是需要大家讨论的,我是在解决楼主问题的时候发现的。
说到这,有人可能会想既然%d对应int,也就是转换4字节的值,那么如果我这样
printf ("%d\n", (float)5.0)
是不是就可以打印出非0值了,因为float是4字节,所以5.0在内存中这回是占用了4字节,所以%d应该能够转换出非0值了。我也是这样想的,并且很有信心会出现预期的结果。
不过。。。
还是打印0 (我是在GNU/Linux平台上测试的)
就算我这样
float i = 5.0;
printf ("%d\n", i);
也还是打印0
我看了printf ("%d\n", (float)5.0)最后压入栈的情况是这样的
movl $0, %eax
movl $1075052544, %edx
pushl %edx
pushl %eax
pushl $.LC9 ; (float) 5.0
call printf
这和printf ("%d\n", 5.0)或者printf ("%d\n", (double)5.0)的情形完全一样
我又看了printf ("%d\n", (float)5.1)的情形,他和printf ("%d\n", 5.1)的情形稍有不同——eax的值差一点——其他都完全一样。
其实不管是5.0还是5.1我发现call printf前都有三次压栈,除去pushl $.LC9是将"%d\n"压入栈,其他两个pushl %edx和push %eax实际就是代入参数5.0或者5.1的值。这两次一共压了8字节,可是我以(float) 5.0作为参数代入时,应该只有4字节啊。所以我怀疑不论是float还是double在作为参数代入printf时,都转换成了8字节(代入普通函数时好像是直接压入栈)。所以打印出的5.0还是为0,因为低4字节凑巧还是0。
当我这样时
float i = 5.0;
printf ("%d\n", i);
我看了汇编代码,情况更加复杂
movl $0x40a00000, %eax ; 0x40a00000 就是 5.0
movl %eax, -4(%ebp)
subl $4, %esp
flds -4(%ebp)
leal -8(%esp), %esp
fstpl (%esp)
pushl $.LC1 ; 将"%d\n"压入栈
call printf
这好像和什么FPU堆栈有关,好像是将所有浮点数转换成10字节,然后代入。
如果我这样
float i = 5.0;
foo (i); // foo的原型是void foo (float)
汇编为
movl $0x40a00000, %eax
movl %eax, -4(%ebp)
pushl -4(%ebp)
call foo
好象是把4字节扩展成8字节,然后压栈。
如果我这样
foo (5.0);
汇编为
movl $0x40a00000, %eax
pushl %eax
call foo
直接压栈。
关于浮点数,gcc编译器为什么会做这样的处理,还有待高人指点迷津。
weping
2005-12-29
打赏
举报
回复
产生不可预料的后果了?
jianwang_yz
2005-12-29
打赏
举报
回复
printf("%d\n", 5.0); //结果是0
printf("%d\n",i);
printf("%d\n",5.0); //结果是5.0000000
printf("%f\n",5); //结果是0.0000
这应该跟库里printf函数的编写有关,是不是得考虑浮点数在内存中的存储问题,记得浮点数载内存中是以定点数形式存放的,即存储一个相应整数,然后再存储小数点的位置,这样当printf函数按%d形式读取时,它就不会考虑形式了,将其当整型读取了!
fiftymetre
2005-12-29
打赏
举报
回复
printf("%f",5.0)你这样呢
waterczh
2005-12-29
打赏
举报
回复
printf("%f",5)也是0,能不能再解释详细一点呢
《你必须知道的495个C语言
问题
》
你难免会遇到各种各样的
问题
,有些可能让你
百思不得其解
,甚至翻遍图书馆,也找不到
问题
的答案。 《你必须知道的495个C语言
问题
》的出版填补了这一空白。许多知识点的阐述都是其他资料中所没有的,弥足珍贵。 涵盖...
你必须知道的495个C语言
问题
.pdf
你难免会遇到各种各样的
问题
,有些可能让你
百思不得其解
,甚至翻遍图书馆,也找不到
问题
的答案。 《你必须知道的495个C语言
问题
》的出版填补了这一空白。书中内容是世界各地的C语言用户多年来在新闻组comp.1ang.c...
C学习:一个
百思不得其解
的无符号数移位
问题
在做一个算法定点化移位过程中,遇到个**
奇怪
问题
**:分别按无符号数和有符号数进行右移,竟然不管啥输入,res1和res2结果都一样。
野指针所引起的
问题
今天运行程序时,遇到了一个很
奇怪
的
问题
,加了几个打印,就会出现死机的情况,去掉就能正常运行,就
奇怪
了,怎么会出现这种情况,最后
百思不得其解
,叫了同事过来看了看,最后发现原来是野指针引起的
问题
。...
2009年4月,总结工作上的2个
问题
,在Broadcom STB上访问MTD, 和修改CFE(a boot loader of broadcom)的
奇怪
的
问题
!
1. 在broadcom 97403 STB上用应用程序直接访问 /dev/mtd0设备(nor flash),交叉编译好后,在STB开发板上一跑,总是存在
问题
,不能获取MTD设备的参数信息...花费了3天时间,
百思不得其解
,很苦恼! 突然,发现一个工具
C语言
69,371
社区成员
243,080
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章