C++ Primer:表达式运算顺序(练习4.33分析解答)


1. 问题

练习4.33:根据4.12节中的表(第147页)说明下面这条表达式的含义。

someValue ? ++x, ++y:--x, --y

2. 分析

  表达式运算顺序的3个决定因素:运算符的优先级,运算符的结合律,运算对象的求值顺序。

优先级:规定复合表达式中运算符组合的方式
前置递增运算符(++) = 前置递减运算符(–) > 条件运算符(?:) > 逗号运算符(,)

注意:若未明确求值顺序,不同子表达式都使用同一对象,若其中某一表达式修改这个对象,会引发错误产生未定义的行为。如下实例,i和++i并未明确先算哪个。若先算i再算++i则输出0和1,若先算++i再算i则输出1和1,具体结果由编译器决定。一般是先用到的先算,即先输出i++则i=1,再输出i,则i是原先i++执行之后的结果。

#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    cout << ++i << " " << i << endl;

    return 0;
}

运算结果

结合律:规定具有相同优先级的运算符如何组合在一起
前置递增运算符(++)、前置递减运算符(–):右结合
条件运算符(?:) :右结合
逗号运算符(,):左结合

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int grade = 70;
    //因为条件运算符是右结合律,故从右向左看。
    // grade > 60 ? "良" : "差"   组成一个包含条件运算符的表达式exp
    // grade > 90 ? "优" : exp    组成另一个包含条件运算符的表达式
    string s1 = (grade > 90 ? "优" : grade > 60 ? "良" : "差");
    string s2 = (grade > 90 ? "优" : (grade > 60 ? "良" : "差"));
    cout << grade << ":" << s1 << " " << s2 << endl;

    //假设条件运算符是左结合律,则从左向右看。
    //grade > 90 ? "优" : grade > 60 组成一个包含条件运算符的表达式exp
    //expr ? "良" : "差"             组成另一个包含条件运算符的表达式
    return 0;
}

运行结果

求值顺序:
逻辑与运算符(&&):先算左侧表达式,若为假,则直接判断表达式为假,若为真,才会再算右侧表达式推出结果。
逻辑或运算符(||):先算左侧表达式,若为真,则直接判断表达式为真,若为假,才会再算右侧表达式推出结果。
条件运算符(?:):若条件为真,则算冒号左侧表达式,若为假,则算冒号右侧表达式。
逗号运算符(,):先算逗号左侧表达式,将结果丢弃。再算逗号右侧表达式,将结果返回。
其它运算符:未明确求值顺序。

#include <iostream>
using namespace std;

int main()
{
    int i = 0;
    int i1, i2, i3;
    int i4 = (i1 = i, i2 = ++i, i3 = --i);

    cout << "i1=" << i1 << endl;
    cout << "i2=" << i2 << endl;
    cout << "i3=" << i3 << endl;
    cout << "i4=" << i4 << endl;

    return 0;
}

运行结果

3. 解答

若someValue =false,x=0,y=0,则程序实际运算过程如下:

#include <iostream>
using namespace std;

int main()
{
    bool someValue = false;
    int x = 0, y = 0;
    
    //原表达式
    someValue ? ++x, ++y : --x, --y;

    //添加括号后的表达式
    (someValue ? ((++x), (++y)) : (--x)), (--y);

    //(++x), (++y), (--x) (--y)虽然优先级高,但它有求值顺序
    //故不能一开始就全部计算,使表达式变成(someValue ? (1, 1) : 0), 0; 
    //应是:先用的先算,未用的不算。
    (false ? ((++x), (++y)) : (--x)), (--y);

    //条件为false,故选择冒号右侧表达式
    (--x), (--y);

    //逗号运算符先算左侧表达式,--x计算结果是x=0-1=-1
    -1, (--y);

    //再算右侧表达式,--y计算结果是y=0-1=-1
    -1,-1;

    //返回右侧表达式计算结果
    -1;

    return 0;
}

若someValue =ture,x=0,y=0,则程序实际运算过程如下:

#include <iostream>
using namespace std;

int main()
{
    bool someValue = true;
    int x = 0, y = 0;

    //原表达式
    someValue ? ++x, ++y : --x, --y;

    添加括号后的表达式
    (someValue ? ((++x), (++y)) : (--x)), (--y);

    //(++x), (++y), (--x) (--y)虽然优先级高,但它有求值顺序
    //故不能一开始就全部计算,使表达式变成(someValue ? (1, 1) : 0), 0; 
    //应是:先用的先算,未用的不算。
    (true ? ((++x), (++y)) : (--x)), (--y);

    //条件运算符中条件为true,执行冒号左侧表达式
    ((++x), (++y)), (--y);

    //逗号运算符先执行左侧表达式,++x计算结果是x=0+1=1
    (1, (++y)), (--y);

    //再执行右侧表达式,++y计算结果是y=0+1=1
    (1, 1), (--y);

    //返回右侧表达式的计算结果
    1, (--y);

    //同理,--y计算结果是y=1-0=0
    1, 0;

    //同理,返回右侧表达式的计算结果
    0;
    
    return 0;
}

总的测试程序:

#include <iostream>
using namespace std;

int main()
{
    int someValue;
    int x, y;

    someValue = false, x = 0, y = 0;
    int i1 = (someValue ? ++x, ++y : --x, --y);
    cout << "someValue=" << someValue << "\tx=" << x << "\ty=" << y << "\ti1=" << i1 << endl;

    someValue = true, x = 0, y = 0;
    int i2 = (someValue ? ++x, ++y : --x, --y);
    cout << "someValue=" << someValue << "\tx=" << x << "\ty=" << y << "\ti2=" << i2 << endl;

    //等价于
    cout << "--------------------------------------------" << endl;
    someValue = false, x = 0, y = 0;
    int i3 = ((someValue ? ((++x), (++y)) : (--x)), (--y));
    cout << "someValue=" << someValue << "\tx=" << x << "\ty=" << y << "\ti3=" << i3 << endl;

    someValue = true, x = 0, y = 0;
    int i4 = ((someValue ? ((++x), (++y)) : (--x)), (--y));
    cout << "someValue=" << someValue << "\tx=" << x << "\ty=" << y << "\ti4=" << i4 << endl;
}

测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值