高分求教cout输出问题!在线等!

zcphoenix 2007-08-11 03:48:10
#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

请高手指点一下!
不胜感激!
...全文
838 37 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
sq901003 2012-03-31
  • 打赏
  • 举报
回复
顶34层说的,这个跟栈好像没有什么关系吧, cout输出中间只是一个缓冲区,把要输出的数据,插入到流中,进入缓冲区的
LKStudio 2008-08-21
  • 打赏
  • 举报
回复
受益匪浅啊。。。
donnychou 2007-08-12
  • 打赏
  • 举报
回复
got it
sbgeqh 2007-08-12
  • 打赏
  • 举报
回复
看了以上的,应该都明白了
gfxiang 2007-08-12
  • 打赏
  • 举报
回复
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)等等
SimerJoe 2007-08-12
  • 打赏
  • 举报
回复
首先cout那句是从右往左执行的,
第一次调用foo由foo里面的cout输出: 第1次调用 此时return ++x 相当于 return 2
第二次调用foo由foo里面的cout输出: 第2次调用 此时return ++x 相当于 return 3
最后由main函数里面的cout输出: 2 3
lgdgyd2 2007-08-12
  • 打赏
  • 举报
回复
mark,研究一下!
missilery 2007-08-12
  • 打赏
  • 举报
回复
同步
临界区
nankezhishi 2007-08-12
  • 打赏
  • 举报
回复
cout << a(XXX) << b(XXX) << endl;

先计算b(XXX); 结果比如是“bbb”;

再计算a(XXX); 结果比如是 “aaa”;

在完成这两个函数运算之前,这个语句不会cout出任何东西
(函数a、b里的输出语句会直接输出,所以LZ代码先输出了两行有文字的)

这两个计算完了。上面的语句相当于

cout << "aaa" << "bbb" << endl;

然后运行这个语句。与缓冲区没有关系,与堆栈也没有关系。虽然看起来像个堆栈的效果

至于为什么要先计算右面的函数。

C++的设计者BS说,C++标准没有规定应该先计算哪个。都可以。

但是从编译器设计的角度来说,先计算右面的会给设计带来方便。所以就先计算右面的了。

有兴趣的可以去找本编译原理书,看看“语法分析”部分。
shinyix 2007-08-12
  • 打赏
  • 举报
回复
gfxiang(afu) 的说法是正确的
zcphoenix 2007-08-12
  • 打赏
  • 举报
回复
我个人觉得‘gfxiang(afu)’的解释是正确的,但是我还想问一下:
cout << foo(i) << "\t" << zoo(i) << endl;
对于这样的语句,为什么编译器多是选择从右至左的函数执行顺序?而不是从左至右呢?
这样选择是不是对代码的优化有什么好处?还是会带来其它方面的好处呢?
谢谢!
onlinewan 2007-08-11
  • 打赏
  • 举报
回复
这个啊,就是函数的执行过程的问题,也就是栈操作问题.

要等子调用的函数都执行完了,才能继续执行自己.
loops 2007-08-11
  • 打赏
  • 举报
回复
takecareofmyself() 所说的那个缓冲区就是栈,我以为说的是cout内部的buffer。
loops 2007-08-11
  • 打赏
  • 举报
回复
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)

wyjkk 2007-08-11
  • 打赏
  • 举报
回复
我干脆总结一下吧:
原始输出语句: cout << foo(i) << '\t' << foo(i) << endl;

从又向左执行
1:执行<<endl,因为没有std::cout对象,无法执行,压栈

2:执行<<foo(i),执行foo(1),输出:第1次调用,得到返回值2,还是因为没有std::cout对象,无法马上输出,压栈
此时,代码变成cout << foo(i) << '\t' << 2 << endl;

3:执行<< '\t' ,没有std::cout对象,无法马上输出,压栈
此时,代码变成cout << foo(i) << '\t' << 2 << endl;

4:执行<<foo(i),执行foo(2),输出:第2次调用 得到返回值3,还是因为没有std::cout对象,无法马上输出,压栈
此时,代码变成cout << 3 << '\t' << 2 << endl;

输出上面的代码,OK,就是LZ看到的。
wyjkk 2007-08-11
  • 打赏
  • 举报
回复
我干脆总结一下吧:
原始输出语句: cout << foo(i) << '\t' << foo(i) << endl;

从又向左执行
1:执行<<endl,因为没有std::cout对象,无法执行,压栈
2:执行<<foo(i),执行foo(1),
输出:第1次调用


cnssccgg 2007-08-11
  • 打赏
  • 举报
回复
在执行这条语句cout << foo(i) << '\t' << foo(i) << endl;时,首先依次调用了两个foo(i),于是屏幕上出现了“第1次调用 第2次调用”,同时将两个返回值压入堆栈,这时,
cout << foo(i) << '\t' << foo(i) << endl语句,就变成了
cout <<‘3’<< '\t' <<‘2’ << endl;
wyjkk 2007-08-11
  • 打赏
  • 举报
回复
takecareofmyself() ( ) 信誉:100
正确
jayfer 2007-08-11
  • 打赏
  • 举报
回复
进程空间:
代码区----------------存放程序的执行代码
全局数据区------------存放全局数据,常量,文字量,静态全局量和静态局部量
堆区------------------存放动态内存,供程序随机申请使用
栈区------------------函数数据区(局部数据区)
(以上是运行中的内存布局)


函数调用的整个过程就是栈空间操作的过程。函数调用时,C++作以下工作:
(1)建立被调函数的栈空间,其大小由函数定义体中的数据量决定;
(2)保护调用函数的运行状态和返回地址;
(3)传递参数;
(4)将控制权转交给被调函数;
(5)函数运行完成后,复制返回植到函数局部数据块底部;
(6)恢复被调函数的运行状态;
(7)返回调用函数。

调用一个函数可以看作是一个栈中元素的压栈与退栈操作。
MPTD_Fire 2007-08-11
  • 打赏
  • 举报
回复
lz
我给你个解析

对于cout输出不压入堆栈,直接输出。而参数要压入堆栈,所以输出是3,2

不知道对不?
加载更多回复(17)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧