C++-一个关于c++ 输出流的疑问

前端开发 前端开发 主题:1148 回复:2395

C++-一个关于c++ 输出流的疑问

偏爱自由 发布于 2016-12-03 字数 284 浏览 1182 回复 10
#include<iostream>
using namespace std;
int display()
{
cout<<"哈哈哈哈哈";
return 1;

}
int main()
{
cout<<"="<<2<<display()<<3<<endl;
return 0;
}

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

支持 Markdown 语法,需要帮助?

评论(10

夜无邪 2017-09-06 10 楼

在处理cout、printf这些函数的时候,会先把他们的参数从右到左压入栈中。
你上面的例子,首先是3,然后是display(),这个时候函数已经执行了,并且把返回值1压入栈中,接着就是2和等号。
所以得到你上面的结果也是理所当然的,在函数式编程中,这个问题会很清晰~

泛泛之交 2017-09-04 9 楼

from ostream chaining, output order
The following (I removed std::endl for simplicity)

 std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
std::cout << "Hello, world!" << print( std::cout );
is equivalent to this:

std::operator(operator<<(std::cout, "Hello, World!"), print(std::cout));
which is a function call, passing two arguments:

First argument is : operator<<(std::cout, "Hello, World!")
Second argument is : print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).

清晨说ぺ晚安 2017-08-27 8 楼

Update:2012-08-23

其实这个程序的执行结果是和编译器有关的,由参数的压栈顺序决定,而且各个编译器比如VS和GCC的函数参数入栈顺序是可以设置的。

一般默认是从右往左。因此你的程序得出的结果是这样的。

C/C++允许使用多种调用约定,这些调用约定是编译器相关的.
在Vc里默认调用约定是可调的,在工程设置里选择:
调用约定 堆栈清除 参数传递
cdecl 调用者 从右到左,通过堆栈传递
stdcall 函数体 从右到左,通过堆栈传递
fastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈
thiscall 函数体 this指针默认通过ECX传递,其它参数从右到左入栈
C++Builder6:
调用约定 堆栈清除 参数传递
fastcall 函数体 从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用堆栈
pascal 函数体 从左到右,通过堆栈传递
cdecl 调用者 从右到左,通过堆栈传递
stdcall 函数体 从右到左,通过堆栈传递(与VC中的stdcall兼容)
msfastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈(兼容VC的fastcall)
Gcc里也可以使用attribute关键字控制参数的传递方式.

有C++标准为证:

Order of evaluation of function arguments is unspecified, from C99 §6.5.2.2p10:

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

Similar wording exists in C89.

Additionally, you are modifying pa multiple times without intervening sequence points which invokes undefined behavior (the comma operator introduces a sequence point but the commas delimiting the function arguments do not). If you turn up the warnings on your compiler it should warn you about this:

$ gcc -Wall -W -ansi -pedantic test.c -o test
test.c: In function ‘main’:
test.c:9: warning: operation on ‘pa’ may be undefined
test.c:9: warning: operation on ‘pa’ may be undefined
test.c:13: warning: operation on ‘pa’ may be undefined
test.c:13: warning: operation on ‘pa’ may be undefined
test.c:17: warning: operation on ‘pa’ may be undefined
test.c:17: warning: operation on ‘pa’ may be undefined
test.c:20: warning: control reaches end of non-void function

The order that function parameters are evaluated is unspecified behavior. (This won't make your program crash, explode, or order pizza... unlike undefined behavior.)

The only requirement is that all parameters must be fully evaluated before the function is called.

This:

// The simple obvious one.
callFunc(getA(),getB());
Can be equivalent to this:

int a = getA();
int b = getB();
callFunc(a,b);
Or this:

int b = getB();
int a = getA();
callFunc(a,b);
It can be either; it's up to the compiler. The result can matter, depending on the side effects.

参考:
资料1
资料2

泛泛之交 2017-08-06 7 楼

在处理cout时先 把cout语句的内容从右到左压进栈,而函数在压栈过程中已经输出。

就你的问题而言,是先执行了display语句。

甜柠檬 2017-05-22 6 楼

貌似没那么复杂吧,cout输出的是display()的返回值,当然会先执行display函数,所以就想输出:哈哈哈

清晨说ぺ晚安 2017-05-20 5 楼

感觉这个表达式等价于
f(f(f(f(cout, =), 2), display()), 3)
函数参数的求值顺序貌似是未定义的吧?

虐人心 2017-03-30 4 楼

因为要输出display()的返回值,所以必须在执行cout语句之前执行display()函数。这种解释比较容易理解,具体为什么还要看上面大师引用的文档。

浮生未歇 2017-01-29 3 楼

在代码里都是通过cout对象输出,操作的是同一个缓冲区,因此,缓存不会影响结果。而从结果反推,是先执行了 display()

想挽留 2016-12-28 2 楼

 cout<<"="<<2<<display()<<3<<endl;
0022150E mov esi,esp
00221510 mov eax,dword ptr [imp_std::endl (22A314h)]
00221515 push eax
00221516 mov edi,esp
00221518 push 3
0022151A call display (221118h)
0022151F mov ebx,esp
00221521 push eax
00221522 mov eax,esp
00221524 push 2
00221526 push offset string "=" (227840h)
0022152B mov ecx,dword ptr [imp_std::cout (22A300h)]
00221531 push ecx
00221532 mov dword ptr [ebp-0C4h],eax
00221538 call std::operator<<<std::char_traits<char> > (22114Ah)
0022153D add esp,8
00221540 mov ecx,eax
00221542 call dword ptr [
imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (22A318h)]
00221548 mov ecx,dword ptr [ebp-0C4h]
0022154E cmp ecx,esp
00221550 call @ILT+400(
RTC_CheckEsp) (221195h)
00221555 mov ecx,eax
00221557 call dword ptr [imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (22A318h)]
0022155D cmp ebx,esp
0022155F call @ILT+400(__RTC_CheckEsp) (221195h)
00221564 mov ecx,eax
00221566 call dword ptr [
imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (22A318h)]
0022156C cmp edi,esp
0022156E call @ILT+400(RTC_CheckEsp) (221195h)
00221573 mov ecx,eax
00221575 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (22A31Ch)]
0022157B cmp esi,esp
0022157D call @ILT+400(
RTC_CheckEsp) (221195h)

从反汇编看十分明显,整个输出函数是个栈,参数是从右到左压入栈中的,这样最先压入3,然后压入display(),这时候调用display函数,输出“哈哈哈哈哈”,返回值1保存在eax中,然后eax也被压入栈中,2同样入栈,最后压入的参数是“=”,打印的时候跟入栈相反,即“哈哈哈哈哈”然后是“=”,然后是2、1、3,
最终输出结果是:
哈哈哈哈哈=213

甜柠檬 2016-12-08 1 楼

cout<<"="<<2<<display()<<3<<endl;
这句代码可以理解为

int temp = display();
cout<<"="<<2<<temp<<3<<endl;

这样结果应该就清晰了。