您的位置:首页 > 其它

cout输出流的执行顺序

2016-08-29 00:13 148 查看
下面是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<

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"


这应该只是个测验。我相信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”<
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: