ホームページ  >  に質問  >  本文

c++ - 关于++运算符的一个问题

请问为什么下面代码输出的值为22?
求给出分析过程

#include<stdio.h>

int main(void)
{

    int i=5,j=5;

    int p;
 
    p=(++i)+(++i)+(++i);

    printf("p=%d",p);

    return 0;

}
天蓬老师天蓬老师2714日前590

全員に返信(6)返信します

  • 阿神

    阿神2017-04-17 15:33:45

    一个表达式里面,同一个变量多个++的求值顺序是不确定的,这种行为是未定义的,不同的编译器可能得出不同的结果,不建议写这样的带有副作用的代码。
    关于求值顺序,可以参考一下wiki

    返事
    0
  • 怪我咯

    怪我咯2017-04-17 15:33:45

    如果这是考题,请参考相关考试资料。


    在这里给出C++11/14和C11正确的思路:

    表达式(++i)+(++i)+(++i)的相关顺序规则有,先增的顺序规则(副作用先于值计算)和运算符的顺序规则(运算数的值计算先于运算符结果的值计算)。

    由此可确定的计算顺序:该表达式中,任意++i的副作用和值计算先于相关的+的值结算(+无副作用)且其副作用先于值计算(即先增)。根据+的结合性(从左向右)可得出:第一个+的值计算先于第二个+的值计算。

    不可确定的计算顺序:任意两个++i的值计算和副作用之间均不存在确定的先后关系。

    所以凭直觉,可以根据以上限制,列出一系列可能的计算过程:

    6+7+8 = 13+8
    6+8+7 = 14+7
    7+6+8 = 13+8
    ...

    但问题在于,C++11/14标准中有如下约定:

    (§1.9/15)[...]If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

    C11标准中有如下约定:

    (§6.5/2)If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.[...]

    又因为该表达式中任意两个'++i'之间的副作用顺序是未确定的,所以这在C++11/14和C11中是未定义行为。

    C++11之前和C11之前的规则在这里不加讨论,但根据其标准,也都是未定义行为。

    最后罗嗦一句未定义行为。C++11标准有如下约定:

    (§1.3.24)undefined behavior
    behavior for which this International Standard imposes no requirements
    [Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. — end note ]

    C11标准有如下约定

    (§3.4.3)
    1 undefined behavior
    behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
    2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

    意即,标准对未定义行为的行为不做任何要求,而编译器或运行平台可在编译期或者运行期约定未定义行为的行为也可不约定。在不约定时,程序的行为将完全不可预测。


    如果按谭爷(雾)的思路:(可能是)根据运算符+的结合方式(左结合),得出等价表达式((++i)+(++i))+(++i)。然后推导出,左侧两个++i先计算(大雾),由于先增,等价(7+7)+(++i),等价(7+7)+8(大物),等于22

    问题在于,结合方式和子表达式的值计算顺序没有关系。

    返事
    0
  • 天蓬老师

    天蓬老师2017-04-17 15:33:45

    第一个++i参与运算的结果为6;第二个++i参与运算的结果为7,使第一个也变成了7;同理,第三个参与运算的结果为8,使前2个都变成了8,最后的结果是24.我用的是VS,这是用C++测的。

    同样是VS,用C的结果如下图

    返事
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 15:33:45

    楼上正解,所以撤了答案。

    如果你非要纠结这个问题,可以针对你使用的编译器,将代码编译成汇编,看一下具体发生了什么

    返事
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 15:33:45

    同意 @lianera 答案:这种运算C语言标准并没有规定统一的运算顺序。

    返事
    0
  • PHPz

    PHPz2017-04-17 15:33:45

    额。。说了那么多,其实这问题压根就不在计算顺序上。 加法运算顺序是从左到右。

    p=(++i)+(++i)+(++i);

    第一次加法的时候,猛一看是6+7.然而,第二个++i的自增使它前面(第一个++i)的那个i(6)也变成了7.那么第一步运算的和是14.

    然后14加第3个i(8),就等于22了。

    这个答案仅限于配合SX教科书,实际应用中这么写打断他的腿!当然不同的编译器也会给他脸色。

    返事
    0
  • キャンセル返事