代码之家  ›  专栏  ›  技术社区  ›  Alexander Stolz

i=++i+++i;在C++中

  •  16
  • Alexander Stolz  · 技术社区  · 17 年前

    有人能给我解释一下为什么这个代码会打印14个字符吗?我刚才被另一个学生问到了,我想不出来。

    int i = 5;
    i = ++i + ++i;
    cout<<i;
    
    9 回复  |  直到 8 年前
        1
  •  44
  •   phihag    13 年前

    在C++中,副作用的顺序是不确定的。此外,在单个表达式中修改变量两次没有定义的行为(请参见 C++ standard ,§5.0.4,物理页87/逻辑页73)。

    -Wall (gcc)或 /Wall /W4 (Visual C++)添加到命令行将生成管件警告:

    test-so-side-effects.c: In function 'main':
    test-so-side-effects.c:5: warning: operation on 'i' may be undefined
    test-so-side-effects.c:5: warning: operation on 'i' may be undefined
    

    显然,代码编译为:

    i = i + 1;
    i = i + 1;
    i = i + i;
    
        2
  •  16
  •   Claymore    17 年前

    这是未定义的行为,结果将根据您使用的编译器而有所不同。比如说,, C++ FAQ Lite .

        3
  •  12
  •   Michael Burr    17 年前

    根据C++标准,在一组序列点内修改一次以上的值会导致未定义的行为(第5节第4段):

    除非另有说明,否则 单个操作数的计算 算子与子表达式 单个表达式和顺序 发生副作用的原因是什么 对象应有其存储值 用户最多修改一次 此外,优先值应为 仅为确定值而访问 每一项均应符合第款的规定 产品的允许顺序 全表达式的子表达式; 否则,行为是未定义的。 [示例:

    i = v[i++]; // the behavior is unspecified
    i = 7, i++, i++; // i becomes 9
    i = ++i + 1; // the behavior is unspecified
    i = i + 1; // the value of i is incremented
    

    –结束示例]

    请注意,第二个示例,” i = 7, i++, i++;

    下面是C++标准所说的“未定义行为”的含义:

    1.3.12未定义的行为[定义未定义]

    国际标准没有规定任何要求。当出现以下情况时,也可能会出现未定义的行为 以环境特有的文件化方式进行翻译或程序执行(有无 发出诊断消息),以终止转换或执行(发出诊断消息) 诊断信息)。许多错误的程序构造不会产生未定义的行为;需要对其进行诊断。]

    换句话说,编译器可以自由地执行它想要的任何操作,包括

    1. 做一些实现定义的事情&记录在案,
    2. 有完全不可预测的结果

    因此,我想严格来说,表现出未定义行为的东西不是“非法的”,但根据我的经验,每当C/C++程序中出现表现出“未定义行为”的东西时(除非它是一个扩展),它就是一个bug。我认为将这样的构造称为非法并不令人困惑、误导或误导。

    另外,我认为试图解释编译器是如何达到14的值并没有特别大的帮助,因为这没有抓住要点。编译器几乎可以做任何事情;事实上,当编译器使用不同的优化选项运行时,很可能会得到不同的结果(或者可能会产生崩溃的代码,谁知道呢?)。

    对于那些希望获得更多参考资料或向权威机构申诉的人,以下是一些建议:

    以下是比亚恩·斯特劳斯特鲁普对此事的看法:


    C++标准使用“非法”一词——当描述C++和标准C之间的差异时,使用 static 或 extern

        4
  •  4
  •   bgoncalves    17 年前

    易于理解的您的编译器正在评估 二者都 在执行求和之前递增,而不缓存中间结果。这意味着当你加两次i时,它现在的值是7。

    如果你这样做

    int j=++i; 
    int k=++i;
    
    i = j+k;
    

    你会看到13个。

        5
  •  2
  •   Mr Fooz    17 年前

    在特定的编译器上,它选择先执行两个++操作,然后执行加法。它将代码解释为:

    int i = 5;
    ++i;
    ++i;
    i = i + i;
    cout << i;
    

    这是完全正确的。

        6
  •  1
  •   Brad Gilbert    17 年前

    14 ?

    int i = 5;
    i = ++i + ++i;
    cout<<i;
    
    i = ++i   + ++i   ;
    i = ++(5) + ++(5) ;
    i =    6  +    6  ;
    i = 12;
    
    i = ++i   + ++i   ;
    i = ++i   + ++(5) ;
    i = ++i   +   (6) ;
    i = ++(6) +    6  ;
    i =   (7) +    6  ;
    i = 13;
    
    i = ++i   + ++i   ;
    i = ++i   + ++(5) ;
    i = ++(6) +   (6) ;
    i =   (7) +   (7) ;
    i = 14;
    

    很可能是这样 14 ,因为它使 轻微地

        7
  •  1
  •   Razzupaltuff    17 年前

    我认为,当从语法树的角度来看问题时,问题的答案变得更加清晰:

    我
    |
    =
    |
    +





    在我们的例子中,表达式归结为变量i。

    现在发生的情况是,两个一元表达式修改相同的操作数,因此在添加两个一元表达式的结果之前,代码在计算一元表达式时执行两次++i。

    因此,代码所做的确实是


    ++一,;


    对于i=5,这意味着

    i=i+1//我<-6.
    i=i+1//我<-7.
    i=i+i//我<-14

        8
  •  -1
  •   Gonzalo Quero    17 年前

    因为前缀增量具有优先级:

    int i = 5;
    i = i+1; // First ++i, i is now 6
    i = i+1; // Second ++i, i is now 7
    i = i + i // i = 7 + 7
    cout << i // i = 14
    
        9
  •  -1
  •   plan9assembler    17 年前
     i = i++ + i; //11  
    
     i = i++ + i++; //12
    
     i = i++ + ++i; //13
    
     i = ++i + i++; //13
    
     i = ++i + ++i; //14