谁给解释下啊?

redleafer 2009-12-24 01:16:32
using namespace std;
int abs(int a);
float abs(float a);
double abs(double a);
int main()
{
int a=-5,b=3;
float c=-2.4f,d=8.4f;
double e=-3e-9,f=3e6;
cout<<"a="<<abs(a)<<endl;
return 0;
}
int abs(int a)
{
cout<<"int abs"<<endl;
return (a>=0?a:-a);
}
为什么输出的时候 不先输出"a=",而是先输出"int abs",然后换行 再输出"a=5"??
...全文
109 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
whypp 2009-12-24
  • 打赏
  • 举报
回复
转自代码之诗(hotman_x)

这是一篇旧文字了,今天买了个新的硬盘盒,把那个损坏多年尘封已久的移动硬盘接了上去,在一阴暗角落里找到了一个 txt 文档,一看,居然是好多年前在某论坛回的一个贴子——大概是2001年的事了吧?整理一下,放在这里了。观点好象是有错误,先不细想了。

问题是这样:对于 std::cout << arg1 << arg2 << arg3 << arg4,请问,哪个 operator << 先执行?有一位网友妙用了一下表达式:
std::cout << ((std::clog << 1), arg1) << ((std::clog << 2), arg2) << ((std::clog << 3), arg3) << ((std::clog << 4), arg4)
结果,std::clog 先输出 4,以此为证,认为是第四个 << 先执行。

我的观点如下:

1. 其实际形式为:
// 式 1
std::operator<<(
std::operator<<(
std::operator<<(
std::operator<<(
cout, arg1
),
arg2
),
arg3
),
arg4
);

编译时由外向内“剥开”,加上编译器的因素(见下文),参数恰好从右向左入栈。而
operator<< 执行时仍是从左向右,这样,看起来好象是一个这样的operator:

operator<<(cout, arg1, arg2, arg3, arg4); // 式 2

从汇编代码可以看出,在参数入栈后,后续有多个 operator<< 调用,故式 2 不正确。
而且式 2 与式 1 也不等价,看汇编代码:

(汇编代码已缺,我也懒得补了,呵呵)

可以看到,在每个(除第一个外) operator<< 调用前,都有一个弹栈动作add esp, 8
和一个额外的 push eax 动作,弹栈是清除上一次 operator<< 的入栈参数(一个cout地
址和一个arg),而 eax 中即是上一次 operator<< 调用的返回值,operator<< 的返回
值大家都知道,在这里实际就是 cout 的地址。如果与式 2 等价,则这些弹栈、压栈操
作都是多余的。

最后,由于 std::operator<< 是一个 inline template operator,故其在编译期展
开,因此,编译后的 式1 面目如下:

// 式3
cout.operator <<(arg1)
.operator <<(arg2)
.operator <<(arg3)
.operator <<(arg4)
;

x86 的汇编不支持面向对象的表达方式,故在汇编中看到的表达方式类似下面的 C 函数
调用:

// 式4
LeftShiftOperatorArgType4(
LeftShiftOperatorArgType3(
LeftShiftOperatorArgType2(
LeftShiftOperatorArgType1(
&cout, arg1
),
arg2
),
arg3
),
arg4
);

其中 LeftShiftOperator() 的原型类似于:

ostream* LeftShiftOperatorSomeType(ostream*, SomeType);

我们看到,绕了一圈,式 4 与式 1 是如此的相似……

2. 由此我们了解到,这些参数入栈的方式是由“函数调用的嵌套”加上“C++ 从右向左
的参数缺省压栈顺序”共同决定的。但是,如果 arg4 是函数调用,则还有令人感兴趣
的地方:从式 1 或 式4 中可以看出,arg4 与 LeftShiftOperatorArgType3() 调用
是同为 LeftShiftOperatorArgType4() 的参数,而对于形如:

func0( func1(), func2() ); // 式5

的调用,C++ 不保证 func1() 与 func2() 有任何特定的调用顺序。也就是说,对于这
个问题,C++ 不能保证 arg4 作为一个函数会先执行,C++ 只保证“arg4 的返回值会
先入栈”。

再进一步说,即:arg4 是先调用还是后调用,其结论与参数入栈顺序无关,只与编译器
对 式5 的实现方式有关。

这就是我的结论了,请高手猛力拍砖,庶几可收醍醐灌顶之效也。
zgh1990 2009-12-24
  • 打赏
  • 举报
回复
计算表达式<<abs();要先调用abs();
chenzhuolin1002 2009-12-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 fleeboy 的回复:]
这个问题和编译器没有任何关系。不管你用什么C++编译器结果都是一样的。
程序运行到下面这行时,
cout < < "a=" < < abs(a) < <endl;

暂时停住,去运行abs(a),在该函数中,输出了int abs...
然后再回到原来暂停的地方,继续往下执行,于是输出了a=。

这是程序执行的逻辑,所有的编译器都是一样的。
[/Quote]
同意
whypp 2009-12-24
  • 打赏
  • 举报
回复
调试一下就是到了不知道你用的是vc不 在cout <<"a=" <<abs(a) <<endl; 下断点 一路F10就知道了!
foxpeter 2009-12-24
  • 打赏
  • 举报
回复
楼上程序发掉了
楼上的是这个程序在VC下的运行结果:
#include<iostream>
using namespace std;

int a(){cout<<"a"<<endl;return 1;}

int b(){cout<<"b"<<endl;return 2;}

int c(){cout<<"c"<<endl; return 3;}

int main(){

cout<<a()<<endl<<b()<<endl<<c();
return 0;
}
foxpeter 2009-12-24
  • 打赏
  • 举报
回复

#include<iostream>


using namespace std;

int a(){cout<<"a"<<endl;return 1;}

int b(){cout<<"b"<<endl;return 2;}

int c(){cout<<"c"<<endl; return 3;}

int main(){

cout<<a()<<endl<<b()<<endl<<c();
return 0;
}

结果:
c
b
a
1
2
3
cattycat 2009-12-24
  • 打赏
  • 举报
回复
从右往左计算的,所以先调用abs输出int abs,用printf也是一样的。
yilaozhuang 2009-12-24
  • 打赏
  • 举报
回复

#include <iostream>
using namespace std;
int abs(int a);
float abs(float a);
double abs(double a);
int main()
{
int a=-5,b=3;
float c=-2.4f,d=8.4f;
double e=-3e-9,f=3e6;
cout <<"a=" << abs(a) << "b" << endl; //这里修改了一下
return 0;
}
int abs(int a)
{
cout <<"int abs" << endl;
return (a>=0?a:-a);
}
不是2楼说的那样,cout还是从左向右输出的,我把楼主的程序稍微修改了一下就可以看出这一点。应该是程序运行到cout <<"a=" << abs(a) << "b" << endl;的时候,首先运行函数abs(a),所以先输出int abs
Fleeboy 2009-12-24
  • 打赏
  • 举报
回复
这个问题和编译器没有任何关系。不管你用什么C++编译器结果都是一样的。
程序运行到下面这行时,
cout << "a=" << abs(a) <<endl;

暂时停住,去运行abs(a),在该函数中,输出了int abs...
然后再回到原来暂停的地方,继续往下执行,于是输出了a=。

这是程序执行的逻辑,所有的编译器都是一样的。
foxpeter 2009-12-24
  • 打赏
  • 举报
回复
这里cout运算顺序是从右向左.
所以先运行了abs(a)


但是运算顺序跟编译器相关的,所以可能另外一个编译器就会从左向右计算.
redleafer 2009-12-24
  • 打赏
  • 举报
回复
2楼能说详细点儿吗??
冻结 2009-12-24
  • 打赏
  • 举报
回复
cout < <"a=" < <abs(a) < <endl;
这种东西,换个编译器可能结果就不同了。
redleafer 2009-12-24
  • 打赏
  • 举报
回复

include<iostream>
using namespace std;
int abs(int a);
float abs(float a);
double abs(double a);
int main()
{
int a=-5,b=3;
float c=-2.4f,d=8.4f;
double e=-3e-9,f=3e6;
cout < <"a=" < <abs(a) < <endl;
return 0;
}
int abs(int a)
{
cout < <"int abs" < <endl;
return (a>=0?a:-a);
}
为什么输出的时候 不先输出"a=",而是先输出"int abs",然后换行 再输出"a=5"??




yzx714 2009-12-24
  • 打赏
  • 举报
回复
从右向左计算

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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