cout 计算顺序问题

cout输出流的执行顺序

下面是IBM的一道笔试题

#include <iostream> using namespace std; 
int fun( ) { 
cout << "f" ; return 1; } int main() { 
int i = 1; // cout << i++ << i++ << i++ << endl; cout << "m" << fun() << fun() << fun() << endl; 
return 1; } 
输出fffm111 
问题:cout这种连接写法的输出的执行顺序是啥呢? 
cout<<"m"<<fun1()<<fun2()<<fun3()<<endl; 
<<运算是左结合的。 必然先求cout<<"m"的值,值仍然是cout 
然后试图求cout<<fun1()的值,这必须先求出fun1()的值。整个表达式的值仍然是cout 然后试图求cout<<fun2()的值,这必须先求出fun2()的值。整个表达式的值仍然是cout 
然后试图求cout<<fun3()的值,这必须先求出fun3()的值。整个表达式的值仍然是cout 
最后是cout<<endl的值,值是cout 整个表达式语句以分号结尾 
注意:问题就在这里:“这必须先求出fun1()的值”,“这必须先求出fun2()的值”,“这必须先求出fun3()的值”,这3句。这是计算<<运算的前提。只要分别在计算cout<<fun1(),cout<<fun2(),cout<<fun3(),之前完成就可以了。 
因此,具体是先计算fun1()的值,还是先计算fun2()的值,还是先计算fun3()的值,还是先计算cout<<"m"的值,都不影响表达式的值。 
问题就在这里: 这是个<<表达式。<<本来是位运算,但是这里cout却是来利用运算的“副作用”。 
所谓副作用,就是计算一个表达式的时候,除了得到它的值以外,对环境产生的影响都是副作用。 比如: int a=1,b=2,c=3,d; 
d=a<<b: 
这一步,a<<b计算出1左移2位得到的结果。结果是4。也就是说,赋值表达式结束后,d的值变成4,其它地方都没有改变。这就是说这个<<运算没有副作用。 
但是,cout<<"a"就不一样了。这个表达式的值我们根本就不关心。我们只关心,这个表达式“计算”完以后,"a"被输出到屏幕上了。这里“a被输出到屏幕上”就是副作用。 
   再看这个例子: int foo(int a, int b) { return a+b; } int bar(int a, int b) { return a-b; } int a=1,b=2,c=3,d; d=foo(a,b)+bar(b,d); 
这里,foo()和bar()都没有副作用。因此,这个表达式,不论是先计算foo(a,b)的值,还是先计算bar(b,c)的值,都不会影响计算的结果。 
但是,如果是这个例子: int foo(int* a) { (*a)++; return *a;} int bar(int* a) { (*a)--; return *a;} int a=5,b; b=foo(&a)+bar(&a); 
这个表达式,foo()和bar()都有副作用,所以,先计算foo(&a)还是先计算bar(&a),将直接影响到b的值。 
假如先计算foo,再计算bar。 首先,a=5 计算foo(&a),a变成6,foo(&a)的值是6 
计算bar(&a),a变成5,bar(&a)的值是5 这样,b=6+5=11 假如先计算bar,再计算foo。 
首先,a=5 计算bar(&a),a变成4,foo(&a)的值是4 
计算foo(&a),a变成5,bar(&a)的值是5 这样,b=5+4=9 这就造成了计算结果不一致。    === 那。。。怎么办 一般来说,编c/c++程序有一个纪律:一个语句中不要有两个表达式有副作用。 
典型的这类行为包括:b=(a++)+(a++)+(a++); 
这是典型的违反这条纪律的行为。每个a++都有副作用(改变a的值)。整个表达式的值跟求值顺序直接相连。 还有就是 char* fun() { cout<<"q"; return ""; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; 
每个fun()都有副作用(向屏幕上显示字符)。因此效果直接与求值顺序相关。(而整个表达式的值我们根本就不关心。虽然我知道,值就是cout)。 
====== 
在c/c++中,求值顺序是怎么样的? 
不知道。 
C/C++的规范中,求值顺序是不规定的。这是为了给编译器以优化的空间。 
比如: 
b=(a+2)+(a+2);,那么如果只计算一次a+2的值,而不是两次,那么计算量会大大降低。 
因此, 
不要在C语言里面做这种事情: 
char* fun() { cout<<"q"; return ""; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; 
要这样: 
char* fun() { return "q"; } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 
这样更好: 
string fun() { return string("q"); } 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 
这样就更好了: 
string f="q"; // 隐式转换 
cout<<"m"<<fun()<<fun()<<fun()<<endl; // 输出的一定是 "mqqq\n" 
但是这样不好吗?: cout<<"mqqq"<<endl; 
  这应该只是个测验。我相信IBM的软件工程师们不会编出这种垃圾代码的。

代码稍微修改了下 
#include <iostream> 
using namespace std; 
int fun(int i) { cout << "f"<<i; return i; } 
int main() { 
int i = 1; cout << i++ << i++ << i++ << endl; cout << "m" << fun(1) << fun(2) << fun(3) << endl; cin.get(); return 1; } 
输出结果: 321 f3f2f1m123

如果只针对题来说的话,实际是这样的 
cout<<"m"<<fun()<<fun()<<fun(); 
对于<<其实是从右往左处理的。于是碰到fun()必然先输出f,然后返回1,于是就变成了 
cout<<"m"<<fun()<<fun()<<1; 继续往左走,直到 cout<<"m"<<1<<1<<1 ;的时候已经输出了fff ,之后就是按顺序输出了m111, 所以看到的结果就是 fffm111

系转载,原址:http://www.cnblogs.com/penelope/articles/2426608.html

时间: 2024-12-27 15:06:31

cout 计算顺序问题的相关文章

C/C++知识要点4——printf函数以及cout的计算顺序

printf函数的计算顺序:先从右到左压栈,然后从左到右出栈. 例程: #include"stdio.h" int main() { int arr[] = { 1, 2, 3, 4, 5 }; int *ptr = arr; printf("%d %d\n", *ptr, *(++ptr)); return 0; } 输出:2 ,2 计算顺序:先计算*(++ptr).进行压栈,然后计算*(ptr).再压栈. 注意:++ptr 和 ptr++ 的计算顺序.会导致不同

c语言中printf()函数中的参数计算顺序

今天看到了一个关于printf()函数计算顺序的问题,首先看一个例子: #include<stdio.h> int main() { printf("%d---%d---%d",printf("ab"),printf("c"),printf("eee")); } 输出结果为: 这说明printf()函数在计算的时候顺序是从右往左的,但最后输出的顺序是从左往右的.所以遇到类似题目时,应该根据运算顺序和输出顺序灵活判断

C++ cout执行顺序

C++ cout执行顺序 问题描述是这样的:如果在cout中调用函数,同时这个函数中包含输出语句,那么会先输出哪一句? 仔细一看,突然发现对C++的内容遗忘了,确实一下子看不出来输出的先后问题. 实现如下: 1 int max(int x, int y) 2 3 { 4 5 int max=0; 6 7 max=(x>y)?x:y; 8 9 cout<<"2. max="<<max<<endl; 10 11 return max; 12 13

c++cout执行顺序之一个不容易注意到的一点

二话不说,先看一个例子 #include <iostream> using namespace std; int main() { int a[10]={1,12,34,56,78,89,90,8,9,0}; int *p=a; int *p2=a; cout<<++*p<<endl; cout<<*++p<<endl;//谁靠的近先执行谁 cout<<endl; cout<<++*p2<<" &qu

绘制顺序(draw order)是如何影响 grasshopper 的计算顺序的

一般情况下,grasshopper 的计算是沿着连接线从左至右进行的.首先被计算的是左边的组件,然后触发下游组件,直到 canvas 全部计算完成为止.在你使用 grasshopper 几个月之后,想都不用想就知道这是当然的. 直到有一天你想用 grasshopper 违反这个基本逻辑.我最近接到一个任务,需要用 Honybee 计算强光.强光计算组件使用了一个 Rhino 相机,这意味着当强光将要被正确计算的时候,相机要移动到正确的位置. 我决定使用霍斯特相机控制(Horseter camer

关于rem的计算顺序

/*响应式字体*//* * 字体响应式 * 屏幕>640px时,html字体大小 * 屏幕<640px时,html字体根据屏幕做出相应  * */(function(doc,win){    var docEl = doc.documentElement,        resizeEvt = "orientationchange" in window ? "orientationchange" : "resize",       

linux系统下printf函数可变参数的计算顺序

#include<stdio.h>  void main()  {  int i=5;  //printf("%d,%d,\n",i,i++); //输出 6,5, //printf("%d,%d,\n",i++,i); //输出 6,6, //printf("%d,%d,\n",i,++i); //输出 6,6, //printf("%d,%d,\n",++i,i); //输出 6,6, //printf(&qu

算法实验--矩阵连乘

一.实验目的: 熟悉掌握动态规划法设计技术 二.实验要求: 1.按教材所授内容要求,完成“矩阵连乘问题”算法.得到一个完整正确的程序. 2.问题规模:不少于20 3.输出最终结果. 三.实验设备: PC机一台 VC6.0编译软件 四.问题描述: 给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2,…,n-1.要算出这n个矩阵的连乘积A1A2…An.由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序.这种计算次序可以用加括号的方式来确定.若一个矩阵连乘积的

Cout vs printf---缓存与引用,流处理顺序(转ithzhang,知乎郝译钧)

一个知乎问题: VS2013,debug模式int i = 4;cout << i++ << i++ << endl;输出结果:54int i = 4;cout << ++i << ++i << endl;结果输出:66同样类似的问题出现在如下函数中void myFun(int i1, int i2) {cout << i1 << i2;}从右往左的结合性我理解..但是为什么一个是54,一个是66?满地打滚求解