cout顺序,i++和++i,*p++和*++p

本文详细探讨了C++中cout输出流的顺序,以及i++, ++i, *p++, *++p等操作符的执行规则。通过实例解释了函数调用在输出流中的顺序和副作用,并强调了不依赖求值顺序的编程习惯。同时,讨论了C++标准中未规定求值顺序的原因,以及如何避免潜在的问题。
部署运行你感兴趣的模型镜像

1.cout输出流顺序

cout是从右到左读取参数,如果参数是函数,则先执行函数体,再将返回的值压栈,否则直接将压栈,最后再将栈中的值输出来

#include <iostream>
using namespace std;
int hello1();
int hello2();
int main() 
{
    int a, b;
    cout << "a=" << hello1() << endl << "b=" << hello2() << endl;
    return 0;
}
int hello1()
{
    cout << "hello1" << endl;
    return 1;
}
int hello2() 
{
    cout << "hello2" << endl;
    return 2;
}

其输出为:

hello2
hello1
a=1
b=2

因为cout输出时,先从右往左扫描,将数据读入缓冲区,然后再从左往右输出。所以,从右往左读取缓冲区的时候,先遇到函数hello2(),那么先执行函数,然后将函数的返回值作为数据读取缓冲区。

cout的输出流顺序_吕白_的博客-CSDN博客

2.i++ , ++i 的本质可视为有返回值的函数

T operator ++()                    //++var
{
    var = var+1;
    return var;
}
T operator ++(int dummy)        //var++(dummy)
{
    T tmp = var;
    var = var+1;
    return tmp;  
}

那么同样,cout是从右到左读取参数,若遇到i++,则立即将i的压栈(注意是值,而不是i的引用),再执行i+1;若遇到++i,则先执行i+1,再将i的引用压栈(而不是i的值,是引用!!!);若遇到i,则将i的引用压栈。

 

3.*p++和*++p

p++:等同于:*p;  p += 1;
解析:由于*和++的运算优先级一样,且是右结合。故*p++相当于*(p++),p先与++结合,然后p++整体再与*结合。前面陈述是一种最常见的错误,很多初学者也是这么理解的。但是,因为++后置的时候,本身含义就是先运算后增加1(运算指的是p++作为一个整体与前面的*进行运算;增加1指的是p+1),所以实际上*p++符号整体对外表现的值是*p的值,运算完成后p再加1.

【注意】是运算后p再加1,而不是p所指向的变量*p再加1

 

*++p:等同于 p += 1;    *p;
解析:由于++在p的前面,++前置的含义是,先加1,得到一个新的p(它的值是原来p的值加1)。然后这个新的p再与前面的*结合.

【总结】无论是*p++还是*++p,都是指针p += 1,即p的值+1,而不是p所指向的变量*p的值+1。

++前置与++后置,只是决定了到底是先p += 1,还是先*p。++前置表示先p += 1,再*p。++后置表示先*p,在p += 1;

--前置与--后置的的分析方法++前置与++后置的一样。

 

【补充】  (*p)++  与 ++(*p)

 (*p)++,使用()强制将*与p结合,只能先计算*p,然后对*p整体的值++。

 ++(*p),先*p取值,再前置++,[该值+1后]作为整个表达式的值。

举例:

int a[5]={1,2,3,4,5};
int *p = a;

*p++ 先取指针p指向的值(数组第一个元素1),再将指针p自增1;

cout << *p++; // 结果为 1

cout <<(*p++); // 1

(*p)++ 先去指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2

cout << (*p)++; // 1

cout <<((*p)++) //2

*++p 先将指针p自增1(此时指向数组第二个元素),* 操作再取出该值

cout << *++p; // 2

cout <<(*++p) //2

++*p 先取指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2)

cout <<++*p; // 2

cout <<(++*p) //2

 对*p++与*++p;(*p)++ 与 ++(*p)的理解_请叫我皮皮虾的博客-CSDN博客_*p++和*++p

 

cout输出流的执行顺序

下面是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<<b计算出1左移2位得到的结果。结果是4。也就是说,赋值表达式结束后,d的值变成4,其它地方都没有改变。这就是说这个<<运算没有副作用。 
但是,cout<<"a"就不一样了。这个表达式的值我们根本就不关心。我们只关心,这个表达式“计算”完以后,"a"被输出到屏幕上了。这里“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" 
但是这样不好吗?: cout<<"mqqq"<<endl; 
  这应该只是个测验。我相信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"<<fun()<<fun()<<fun(); 
对于<<其实是从右往左处理的。于是碰到fun()必然先输出f,然后返回1,于是就变成了 
cout<<"m"<<fun()<<fun()<<1; 继续往左走,直到 cout<<"m"<<1<<1<<1 ;的时候已经输出了fff ,之后就是按顺序输出了m111, 所以看到的结果就是 fffm111 

cout 计算顺序问题 - little_by - 博客园 (cnblogs.com)

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>好的,我现在要回答用户关于C++cout输出xx++顺序结果的问题。首先,我需要回忆一下相关的知识点,确保自己理解正确。用户的问题涉及运算符的优先级、求值顺序以及函数参数的求值顺序,这些都是C++中容易出错的地方。 首先,用户提到的xx++的输出顺序。根据C++的标准,函数参数的求值顺序是未指定的(unspecified),也就是说编译器可以自由决定先计算哪个参数。例如,在cout << x << x++这样的语句中,各个参数的求值顺序可能会影响结果。这时候,我需要确认的是,当多个参数传递给运算符<<时,它们的计算顺序是怎样的。 然后,关于后置递增运算符x++的行为,它会在表达式求值之后增加x的值,但返回的是x原来的值。所以,如果x初始为0,那么x++的结果是0,之后x变为1。但是,如果参数的求值顺序不确定,比如先计算x++还是先计算x,就会导致不同的输出结果。 接下来,我需要查看用户提供的引用内容。引用[2][3]提到了运算符重载求值顺序的问题。特别是引用[2]中的例子显示,在cout << func1() << func2()时,输出顺序是func2先执行,然后是func1,导致输出结果的顺序与函数调用顺序相反。这说明在链式调用<<运算符时,参数的求值顺序是从右到左的,这可能是因为运算符的关联性导致的。 另外,引用[3]详细解释了*p++*++p的区别,这里涉及到运算符的结合性求值顺序。虽然后置递增的优先级较高,但实际求值是在表达式之后进行的。这可能类比到x++的情况,即先使用原值,再递增。 引用[4]中的例子显示,当在同一个cout语句中有多个包含i++i--的表达式时,输出的结果可能与预期不同,因为不同的编译器可能会有不同的求值顺序。例如,在VS 2008下,i的初始值为0,但输出i++的结果为-1,这可能是因为求值顺序导致i的值在某个点被修改,从而影响了其他表达式的计算结果。 综合这些信息,可以得出结论:在C++中,当使用cout输出多个表达式时,尤其是涉及有副作用的表达式(如x++),输出的结果取决于参数的求值顺序,而这一顺序是未指定的,由编译器决定。因此,这样的代码可能会导致未定义行为或依赖于编译器的具体实现,应当避免在同一个表达式中混合使用有副作用的运算符输出语句。 接下来,我需要将这些信息整理成一个结构清晰的回答,分点说明问题原因,并给出示例解决方案。同时,根据用户的要求,生成相关问题。</think>关于C++中`cout`输出表达式`x``x++`的行为解析如下: --- ### 一、核心问题分析 1. **运算符的求值顺序** C++标准未规定函数参数运算符操作数的求值顺序。例如,在`cout << x << x++`中: - 编译器可能先执行`x++`再取`x`,或相反,结果因编译器而异[^2][^3]。 - `x++`是后置递增,返回原值后再自增。 2. **副作用与未定义行为** 若同一表达式多次修改同一变量(如`x`),可能导致未定义行为(UB)。但`x``x++`的组合仅在特定顺序下会导致歧义,需具体分析。 --- ### 二、示例与解析 #### 示例1(`x`初始值为0): ```cpp int x = 0; cout << x << " " << x++; // 输出可能是 "0 0" 或 "1 0" ``` - **情况1**(从左到右求值): 先取`x`(输出`0`),再取`x++`(输出`0`,`x`变为1)。 - **情况2**(从右到左求值): 先计算`x++`(输出`0`,`x`变为1),再取`x`(输出`1`)。 #### 示例2(引用[4]中的代码): ```cpp int i = 0; cout << "i=" << i << "i++=" << i++ << "i--=" << i--; ``` - **输出结果**(VS 2008下):`i=0 i++=-1 i--=0` - **原因**: 编译器从右到左求值,先计算`i--`(返回`0`,`i`变为-1),再计算`i++`(返回`-1`,`i`变为0),最后取`i`的值(0)[^4]。 --- ### 三、关键结论 1. **避免依赖求值顺序**: 若表达式包含对同一变量的多次修改或访问,结果可能不可预测。 2. **分离副作用**: 推荐将自增操作与输出语句分离,例如: ```cpp int tmp = x++; cout << x << " " << tmp; // 明确输出x的新值x++的旧值 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值