高分求教cout输出问题!在线等!
#include <iostream>
using namespace std;
int foo(int &x)
{
cout < < "第 " < < x < < "次调用 " < < '\t ';
return ++x;
}
void main()
{
int i = 1;
cout < < foo(i) < < '\t ' < < foo(i) < < endl;
}
为什么会是如此输出:
第1次调用 第2次调用 3 2
请高手指点一下!
不胜感激!
[解决办法]
cout < < 3 < < '\t ' < < 2 < < endl;
这句实际是调用了4次cout::operator < <,函数参数都预先已经压在栈里面了。
004020CB push offset @ILT+400(std::endl) (00401195)
004020D0 lea eax,[ebp-0A4h]
004020D6 push eax
004020D7 call @ILT+615(zoo) (0040126c)
004020DC add esp,4
004020DF push eax
004020E0 push 9
004020E2 lea ecx,[ebp-0A4h]
004020E8 push ecx
004020E9 call @ILT+685(foo) (004012b2)
004020EE add esp,4
004020F1 push eax
004020F2 mov ecx,offset std::cout (00485088)
004020F7 call @ILT+485(std::basic_ostream <char,std::char_traits <char> > ::operator < <) (004011ea)
004020FC push eax
004020FD call @ILT+780(std::operator < <) (00401311)
00402102 add esp,8
00402105 mov ecx,eax
00402107 call @ILT+485(std::basic_ostream <char,std::char_traits <char> > ::operator < <) (004011ea)
0040210C mov ecx,eax
0040210E call @ILT+855(std::basic_ostream <char,std::char_traits <char> > ::operator < <) (0040135c)
[解决办法]
1. C++标准中没有规定表达式的中子表达式的计算顺序(除了逗号表达式和逻辑运算表达式),所以到底怎样计算子表达式依赖具体编译器的实现。比如
int f();
int g();
int i;
i = f() + g();
该表达式中函数的优先级最高,应该先调用函数。
但计算顺序可以是先调用f(),然后调用g(),返回结果相加再赋给i,
也可以是先调用g(),然后调用f(),返回结果相加再赋给i。
具体是那种计算方式C++标准并没有规定,依赖编译器的实现。
所以上面的cout < < foo(i) < < "\t " < < zoo(i) < < endl;也是同样的道理。从汇编代码来看,VC,g++都是先调用zoo()再调用foo()的;而对上面加法表达式是先调用f(),再调用g()的。
这样的调用顺序在C++标准中是没有规定的,只是编译器的实现。
2. < <运算符是左结合的。也就是说
cout < < foo(i) < < "\t " < < zoo(i) < < endl;
在调用两个函数后,变成(这里假设函数调用顺序如1中所说)
cout < < 3 < < "\t " < < 2 < < endl;
然后,依次调用operator < < (ostream&, int), operator < <(ostream&, const char*), operator < <(ostream&, int)等等
[解决办法]
cout < < a(XXX) < < b(XXX) < < endl;
先计算b(XXX); 结果比如是“bbb”;
再计算a(XXX); 结果比如是 “aaa”;
在完成这两个函数运算之前,这个语句不会cout出任何东西
(函数a、b里的输出语句会直接输出,所以LZ代码先输出了两行有文字的)
这两个计算完了。上面的语句相当于
cout < < "aaa " < < "bbb " < < endl;
然后运行这个语句。与缓冲区没有关系,与堆栈也没有关系。虽然看起来像个堆栈的效果
至于为什么要先计算右面的函数。
C++的设计者BS说,C++标准没有规定应该先计算哪个。都可以。
但是从编译器设计的角度来说,先计算右面的会给设计带来方便。所以就先计算右面的了。
有兴趣的可以去找本编译原理书,看看“语法分析”部分。