printf 小函数 大问题-转
2016-01-16 11:54
183 查看
各位C、C++开发的朋友们,有没有想过小小的printf也会有陷阱呢?这篇文章,我们就深入来探究一下(代码均在suse10 32位系统下编译测试通过)。
废话不多说,直接上代码:
结果是多少呢?当然是1,你可能会说。
我们来看一下结果:
果然是1!但是你会不会以为是 a 首先被自动转化成了 int 类型,然后输入为 1的呢?
如果真这么简单,本文到此也该结束了。我们换一个写法:
这次的结果是多少呢?1 和 2?真的吗?我们来看一下结果:
好吧,你可能该惊讶了。然而这个结果的确是对的。
如果你还是觉得不可相信,我们再来看一个代码:
输入结果是:
这是个随机值。也许你会说,不对呀,应该是 1 呀?
这就涉及到 printf 的设计了,printf的第一个参数永远是字符串,他会解析每一个类似 %d 的结构,然后对指针做对应长度的偏移,如%d是4,%lld就是8。(为什么要偏移,请参看这里 从printf谈可变参数函数的实现)
所以,当执行如下代码
实际上两个%d分别取得是 a 的低4字节和高4字节,从而分别是1和0(这里还涉及到大小端的问题,本机是小端存储)。
而对于
也是一样的道理,先取到的uin作为低4字节,而高4字节则完全随机,从而得到了一个很大的随机数。
知道了这个原因,我们可以做一个测试:
uin2比uin先入栈,所以uin2会在高位,uin会在低位。
如果按照我们所解释的,那两个结果应该完全一致,对不对?我们来看一下输出:
的确是一样的~
看完这篇文章,当再看到类型不匹配的printf时,心里是不是会感觉更恐怖?哈哈
废话不多说,直接上代码:
int64_t a = 1;
printf("%d\n", a);
结果是多少呢?当然是1,你可能会说。
我们来看一下结果:
1
果然是1!但是你会不会以为是 a 首先被自动转化成了 int 类型,然后输入为 1的呢?
如果真这么简单,本文到此也该结束了。我们换一个写法:
int64_t a = 1;int b = 2;printf("%d, %d\n", a, b);
这次的结果是多少呢?1 和 2?真的吗?我们来看一下结果:
1, 0
好吧,你可能该惊讶了。然而这个结果的确是对的。
如果你还是觉得不可相信,我们再来看一个代码:
uint32_t uin = 1;printf("%llu\n", uin);
输入结果是:
13827625253599182849
这是个随机值。也许你会说,不对呀,应该是 1 呀?
这就涉及到 printf 的设计了,printf的第一个参数永远是字符串,他会解析每一个类似 %d 的结构,然后对指针做对应长度的偏移,如%d是4,%lld就是8。(为什么要偏移,请参看这里 从printf谈可变参数函数的实现)
所以,当执行如下代码
int64_t a = 1;int b = 2;printf("%d, %d\n", a, b);
实际上两个%d分别取得是 a 的低4字节和高4字节,从而分别是1和0(这里还涉及到大小端的问题,本机是小端存储)。
而对于
1 2
uint32_t uin = 1;printf("%llu\n", uin);
也是一样的道理,先取到的uin作为低4字节,而高4字节则完全随机,从而得到了一个很大的随机数。
知道了这个原因,我们可以做一个测试:
uint32_t uin = 1;uint32_t uin2 = 2;printf("%llu\n", uin, uin2); uint64_t uin3 = uin2;uin3 = uin3 << 32;uin3 += uin;printf("%llu\n", uin3);
uin2比uin先入栈,所以uin2会在高位,uin会在低位。
如果按照我们所解释的,那两个结果应该完全一致,对不对?我们来看一下输出:
8589934593 8589934593
的确是一样的~
看完这篇文章,当再看到类型不匹配的printf时,心里是不是会感觉更恐怖?哈哈
相关文章推荐
- 在Linux中安装是使用系统性能监控软件Nmon
- mysql服务启动不了,数据库备份
- Android——通过Uri获取文件的路径
- iOS 开发学习之 User Interface(3)iOS 坐标系和 UILabel 与 UIButton
- RedHat Linux下Samba配置(简单配置)-转
- Java反射机制
- 2009-07-03 19:48 在linux中如何获得微秒精度的时间?-转
- android调试时apk可运行,导出签名的apk后闪退,报找不到class
- Volley框架的二次封装
- VS2013编写的C#程序,在xp下会报错说“不是合法的win32程序”。
- [嵌入式]Ubuntu下mini2440的环境搭建-截图记录-转
- Go学习笔记(3)字符串
- QQ互联登陆出现(1054) Unknown column “conuintoken” in “field list”
- gtkterm ubuntu下好用的串口工具使用心得-转
- struts2的s:iterator 标签 详解
- cd 命令写成shell
- Java基础 注解
- mark!
- 将Vim改造为强大的IDE—Vim集成Ctags/Taglist/Cscope/Winmanager/NERDTree/OmniCppComplete(有图有真相)
- Android自定义Button并设置不同背景图片的方法