社区
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的程序,没有成功,谁能解释一下啊。
...全文
632
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,能不能再解释详细一点呢
c语言中
printf
错误,C语言中
printf
输出的
奇怪
错误
本文探讨了C语言中
printf
函数对于不同类型变量的格式化输出
问题
。通过具体示例,详细分析了当输出格式与变量类型不符时产生的未定义行为及其背后的原因。
有关
printf
的小
问题
本文探讨了C++迭代器和C语言结构体在使用
printf
打印时遇到的
奇怪
现象,分析了背后的原因,并介绍了C/C++中的调用约定及其对打印结果的影响。
一个
printf
打印格式不对造成的
奇怪
现象,平常很容易忽略
在调试网络时,发现初始化计数器后,rx包数目打印结果时而为0时而不为0,经过调试发现是
printf
的格式化字符串使用不当导致的。文章通过示例代码展示了使用错误的格式化字符%u打印64位变量时,打印结果可能出现随机错误,而使用正确的%llu格式则能正确打印。总结强调了正确使用
printf
格式化字符的重要性。
printf
函数缓冲区
问题
本文通过一个测试例子揭示了Linux下
printf
函数在不同情况下的缓冲区行为。
printf
的输出在全缓冲区、行缓冲区和非缓冲区三种模式下有不同的刷新规则。在终端输出时,由于行缓冲区的存在,换行符可以触发刷新,但在标准输出被重定向到文件时,
printf
使用全缓冲区,换行符不再能刷新缓冲区,需要手动调用fflush(stdout)来确保数据正确输出。
printf
非常
奇怪
的参数
问题
在使用VS2013进行代码开发时,遇到一个遗留
问题
:代码能通过编译但在运行至最后一步时出现错误。作者寻求社区中熟悉此
问题
的专家提供解决方案。
C语言
70,038
社区成员
243,247
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章