printf-小代码,大问题

标签: 算法 | 发表时间:2011-09-05 14:04 | 作者:Dante mandelbrot89
出处:http://www.blogread.cn/it/

标签:  printf

各位C、C++开发的朋友们,有没有想过小小的printf也会有陷阱呢?这篇文章,我们就深入来探究一下(代码均在suse10 32位系统下编译测试通过)。
废话不多说,直接上代码:

1
2
int64_t a = 1;
printf("%d\n", a);

结果是多少呢?当然是1,你可能会说。
我们来看一下结果:

1

果然是1!但是你会不会以为是 a 首先被自动转化成了 int 类型,然后输入为 1的呢?
如果真这么简单,本文到此也该结束了。我们换一个写法:

1
2
3
int64_t a = 1;
int b = 2;
printf("%d, %d\n", a, b);

这次的结果是多少呢?1 和 2?真的吗?我们来看一下结果:

1, 0

好吧,你可能该惊讶了。然而这个结果的确是对的。
如果你还是觉得不可相信,我们再来看一个代码:

1
2
uint32_t uin = 1;
printf("%llu\n", uin);

输入结果是:

13827625253599182849

这是个随机值。也许你会说,不对呀,应该是 1 呀?

这就涉及到 printf 的设计了,printf的第一个参数永远是字符串,他会解析每一个类似 %d 的结构,然后对指针做对应长度的偏移,如%d是4,%lld就是8。(为什么要偏移,请参看这里 从printf谈可变参数函数的实现
所以,当执行如下代码

1
2
3
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字节则完全随机,从而得到了一个很大的随机数。
知道了这个原因,我们可以做一个测试:

1
2
3
4
5
6
7
8
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时,心里是不是会感觉更恐怖?哈哈

您可能还对下面的文章感兴趣:

  1. printf格式控制(你所不知道的printf妙用) [2009-11-20 21:05:54]

相关 [printf 代码 问题] 推荐:

printf-小代码,大问题

- mandelbrot89 - IT技术博客大学习
各位C、C++开发的朋友们,有没有想过小小的printf也会有陷阱呢. 这篇文章,我们就深入来探究一下(代码均在suse10 32位系统下编译测试通过). 但是你会不会以为是 a 首先被自动转化成了 int 类型,然后输入为 1的呢. 如果真这么简单,本文到此也该结束了. 如果你还是觉得不可相信,我们再来看一个代码:.

Java静态代码块的问题

- - ITeye博客
在查看别人代码的时候 看到了 static静态代码块  之后经过搜索和自己的亲试,下面贴出测试代码和解释. System.out.println("父类--静态代码块");. System.out.println("父类--构造方法");. System.out.println("父类--非静态代码块");.

关于时间旅行的几个问题——解密《源代码》

- Mill - 微科幻 - 果壳网
一辈子很长,经过无数岔口,面临无数选择题. 那些影响人生至关重要的选择题,如果做错了怎么办——你一定有做错过或者后悔过的时候,对吧. 毕竟人生那么长,总有那么个把蛋疼的瞬间会去想“如果我那时……”. 问题的复杂性在于人们只能质疑现有选择的正确性,却无法保证其他选择项的正确性. 如果能在选择前找到所有正确选择项,造就出一条完全正确的人生之路,那无疑,人类的幸福将再也不是多愁善感诗人们笔下的缥缈之物.

关于PHP的is_a()函数执行代码的问题

- Sam - 大风起兮云飞扬
    今天看到云舒在群里贴的漏洞公告,原始的文章在.     后来查了下PHP官方的手册,这个问题是在PHP 5.3.7中更新了is_a()函数的功能. is_a()经常被用于条件判断.     在此前版本的is_a() 的第一个参数如果不是object,则会返回false,现在变成了如果不是object ,则会去执行 __autoload()函数.

不改一行代码定位线上性能问题

- - crossoverJie's Blog
最近时运不佳,几乎天天被线上问题骚扰. 前几天刚解决了一个 HashSet 的并发问题,周六又来了一个性能问题. 我们提供出去的一个 OpenAPI 反应时快时慢,快的时候几十毫秒,慢的时候几秒钟才响应. 由于这种也不是业务问题,不能直接定位. 所以尝试在测试环境复现,但遗憾的测试环境贼快. 中途有抱着侥幸心里让运维查看了 Nginx 里 OpenAPI 的响应时间,想把锅扔给网络.

从教女友写代码中学到的,教人写代码在一定程度上是硬件问题

- - 博客园_新闻
英文原文: Teaching Someone To Code Is Partly A Hardware Problem. 从今年四月一直到七月,我在教我女友写代码. 我最大的收获是认识到了教人写代码在一定程度上是个硬件问题. 虽然 codecademy、可汗学院、Scratch 和其他机构为了教学优化了代码编辑器,但代码编辑器总是卡在它们的软件外壳上.

当cpu飙升时,找出php中可能有问题的代码行

- - IT技术博客大学习
   当你发现一个平时占用cpu比较少的进程突然间占用cpu接近100%时,你如何找到导致cpu飙升的原因. 我的思路是,首先找到进程正在执行的代码行,从而确定可能有问题的代码段. 然后,再仔细分析有问题的代码段,从而找出原因.    如果你的程序使用的是c、c++编写,那么你可以很容易的找到正在执行的代码行.

相亲相爱:Facebook 通过检查 Android 源代码修复应用问题

- - 极客公园-GeekPark
记者,愿意为创新的传播尽绵薄之力,并一直相信理想主义情怀才是原动力. [核心提示]由于 Android 系统的开放性,不止可以让更多人有机会改良系统,也能让开发者更好的解决应用的问题, 并使系统更加完善. 昨天的 极客早知道里,我们报道了 Facebook 移动为先的战略,其发展重心早已由桌面平台转移至移动平台.

程序员写代码时应该反复问自己的10个问题

- - 外刊IT评论
你想成为一名优秀的程序员吗. 那么,现在是时候放下《24小时学会xxx语言v8.3》超级骗子书,相反,你应当 养成每天反问自己以下10个问题的习惯. 找寻模式中的可行与不可行将发现其中看似无关的想法或基本原则. 要对工作达到深入的理解,你必须养成反问自己“是否有一种模式存在. 是否有适应各类型商业变化的模式吗.

那位提问的开发者,可否组织好你的提问和代码再把问题丢出来啊?—— 如何有条理地提问

- - SegmentFault 最新的文章
在 segmentfault 泡了一段时间了,看了很多提问,也回了一些,一般就自己所在的开发方向相关的问题会点进去看,但是有很大一部分是点进去,看一眼就叉了,其中一些是自己解决不了的,更多的是不懂题主在问什么、或题主明显就想要个答案让答主填个空而已、或这个问题搜一下就可以解决的、或代码上百行贴出来的......总之,这些问题“问题”本身有各种各样的“问题”.