1.printf()的参数执行顺序是从右往左的!
为什么呢?我觉得printf()用到了数据结构栈,栈先进先出,那样的话就按我们想要的顺序输出了,那么printf的实现可能就是先将参数计算好了,然后入栈。在输出的时候弹栈,就得到了我们想要的结果!(但具体是如何,我也不清楚,但这跟cout的输出原理很像)。
验证:
#include <stdio.h> int f1() { printf("f1()\n"); return 1; } int f2() { printf("f2()\n"); return 2; } int f3() { printf("f3()\n"); return 3; } void main() { printf("%d,%d,%d\n",f1(),f2(),f3()); }
输出结果:
///////////////////////////转载自http://hi.baidu.com/andyzcj/blog/item/5e2ef7a9cef1dfbfcb130ce8.html
另外关于下面程序的解释:
int i=7; printf("%d\n", i++ * i++);
输出结果是:49而不是56
int i=7;printf("%d %d\n",++i,i++);
输出结果是:8 7而不是9,7 这并不违背分割新上面关于printf函数从右向左计算的原因。
产生这种结果的原因是:
以下内容引自:《C-FAQ》http://c-faq-chn.sourceforge.net/ccfaq/node1.html
尽管后缀自加和后缀自减操作符 ++ 和 -- 在输出其旧值之后才会执行运算, 但这里的``之后"常常被误解。没有任何保证确保自增或自减会在输出变量原值之后和对表达式的其它部分进行计算之前立即进行。也不能保证变量的更新会在表达式 ``完成" (按照 ANSI C 的术语, 在下一个 ``序列点" 之前, 参见问题 3.7) 之前的某个时刻进行。本例中, 编译器选择使用变量的旧值相乘以后再对二者进行自增运算。
包含多个不确定的副作用的代码的行为总是被认为未定义。(简单而言, ``多个不确定副作用" 是指在同一个表达式中使用导致同一对象修改两次或修改以后又被引用的自增, 自减和赋值操作符的任何组合。这是一个粗略的定义; 严格的定义参见问题3.7, ``未定义" 的含义参见问题11.32。) 甚至都不要试图探究这些东西在你的编译器中是如何实现的 (这与许多 C 教科书上的弱智练习正好相反); 正如 K&R 明智地指出, ``如果你不知道它们在不同的机器上如何实现, 这样的无知可能恰恰会有助于保护你。begintex2html_deferred
4.7 我怎样才能理解复杂表达式?``序列点" 是什么?
序列点是一个时间点(在整个表达式全部计算完毕之后或在 ||、 &&、 ? : 或逗号 运算符处, 或在函数调用之前), 此刻尘埃落定, 所有的副作用都已确保结束。 ANSI/ISO C 标准这样描述:
在上一个和下一个序列点之间, 一个对象所保存的值至多只能被表达式的计算修改一次。而且前一个值只能用于决定将要保存的值。
第二句话比较费解。它说在一个表达式中如果某个对象需要写入, 则在同一表达式中对该对象的访问应该只局限于直接用于计算将要写入的值。这条规则有效地限制了只有能确保在修改之前才访问变量的表达式为合法。例如 i = i+1 合法, 而 a[i] = i++ 则非法 (参见问题3.1)。
参见下边的问题 3.8。
4.1 为什么这样的代码: a[i] = i++; 不能工作? 子表达式 i++ 有一个副作用 --- 它会改变 i 的值 --- 由于 i 在同一表达式的其它地方被引用, 这会导致无定义的结果, 无从判断该引用(左边的 a[i] 中)是旧值还是新值。(注意, 尽管在 K&R 中建议这类表达式的行为不确定, 但 C 标准却强烈声明它是无定义的, 参见问题11.32。
///////////////////////////////////////////////////////////////////////////////////////////////////////////
2.cout的输出顺序
还是上面的程序:
#include <iostream> using namespace std; int f1() { cout<< "f1()" << endl; return 1; } int f2() { cout<< "f2()" << endl; return 2; } int f3() { cout<< "f3()" << endl; return 3; } void main() { cout<<f1()<<f2()<<f3()<<endl; }
结果:
可见cout与printf类似的原理:
总结:
1.cout和printf的参数入栈顺序是从右往左的。
2.cout和printf的参数计算顺序也是从右往左的。
3.但是最好不要再输出中调用函数,这样虽然简便但由于不同的编译器可能有不同的结果!
本文探讨了C语言中printf函数及C++中cout对象的参数处理顺序。详细解释了printf参数从右向左计算的原因,并通过实例展示了可能引发的未定义行为。同时对比了cout的输出顺序。
424

被折叠的 条评论
为什么被折叠?



