如题。之所以会思考这个问题,是因为下面的两行代码,竟然没想明白...这可是来自学妹...学妹...学妹的代码啊...

显然这段程序是无法单步调试的,那它的内部到底是怎样执行的呢?不妨先看一眼这几行代码的汇编:

汇编

从汇编程序我们大概能了解到程序实际运行的时候是如何执行的,那么又为什么会这样执行呢。接下来简单看一下printf的内部实现:

从这段代码中,我们可以看到格式、可变参数列表、缓冲区、断言,加锁、返回值,标准写等等,那么具体来讲,printf又是以怎样的机制把参数列表里面的值逐次打印的,举个栗子:

输出结果又一次超出了预期...实际上,绝大多数的C编译器,默认情况下,参数压栈的顺序(读入缓冲区的顺序)是由右向左的,最后弹栈从左向右依次输出。(1)如果参数是函数,则先执行函数体,再将返回的值压栈。(2)若遇到y++,则立即将y的值压栈,再执行y = y + 1;若遇到++y,则先执行y = y + 1,再将y的引用(地址)压栈;若遇到y,直接将y的引用压栈。上面的栗子,如果把y定义成全局变量,结果就又不同了,还没来得及仔细分析,应该是全局的时候只是把值压栈了。

ok,学妹的问题基本上是解决了~既然提到了,顺便也扯一下cout吧,先看一段来自/usr/include/c++/4.9/ostream的源码,不得不吐槽写的真是丑:

ostream

其实cout的输出机制和printf是类似的,只是有几个点需要注意:(1)cout是ostream类的流对象,返回的是一个ostream类型的引用,从图中运算符重载的部分代码可以看出来。(2)这个该怎么理解呢?继续举栗子,cout << a << f():其中cout<<a的实质是cout对象调用其成员函数operator<<(),即cout.operator<<(a),返回一个ostream类型的引用,那么cout << a << f()其实就是cout.operator<<(a).operator<<(f());(3)为什么要这样做呢?和左值表达式有关~

嗯,差不多就酱。