为什么 `++a++`在C++中不能编译,但 `(++a)++`可以?

6
标题所说的。对于C++,(++a)++是可以编译的。但是很奇怪的是,++(a++)却不行:
int main() {
    int a = 0;
    ++a++; // does not compile
    (++a)++; // does compile
    ++(a++); // does not compile
}

但在Java中,并非所有三个都适用:

public class Test {
    public static void main(String[] args) {
        int a = 0;
        ++a++; // does not compile
        (++a)++; // does not compile
        ++(a++); // does not compile
    }
}

为什么C++可以编译这个程序而Java不行?


什么是C++编译器?你觉得a++是一个“void”语句的意义是什么? - Fred Larson
@FredLarson 我在ideone.com上使用了C++11编译器,但我认为任何C++编译器都可以使用。我认为它是一个void语句,因为它在功能上等同于:a = a+1;这不会给出实际值。 - Ryan Dougherty
"...a parser using only one-token lookahead and no semantic analysis during the parse would not be able to tell, when ++ is the lookahead token, whether (p) should be considered a Primary expression or left alone for later consideration as part of a CastExpression." - azurefrog
@Ryan:你的理解是错误的。a++ 返回的是自增前的 a 值。 - Fred Larson
@ControlAltDel 想象一下,如果要弃用这些运算符,需要改变多少代码,几乎所有的C和C++代码都使用这些运算符。 - Shafik Yaghmour
显示剩余4条评论
1个回答

11

所有的Java示例都无法工作,因为后缀和前缀递增操作都返回而不是变量, 我们可以通过查看JLS上的后缀递增运算符++来了解这一点,例如:

后缀递增表达式的结果不是变量,而是值。

前缀递增运算符 ++ 也有相同的说明。

这就像尝试递增一个文字值一样(在此处查看实例):

2++ ;
++3 ;

会产生以下错误:

required: variable
found:    value

这是我们在您示例中遇到的相同错误。

在C++中,前缀递增返回一个左值,但后缀递增返回一个纯右值,并且在C++中,前缀和后缀递增都需要一个左值。因此,您的第一个和第三个C++示例:

++a++;
++(a++)

失败是因为您试图将前缀递增应用于 prvalue。而第二个 C++ 示例:

(++a)++;

因为前缀递增运算符返回一个左值,所以这样做是可以的。

参考C++标准中第5.2后缀表达式(Postfix expressions)的规定:

后缀++表达式的值是其操作数的值[...] 操作数必须是可修改的左值

还有:

结果是一个纯右值(prvalue)

而第5.3一元表达式(Unary expressions)则如下描述:

前缀++的操作数被修改[...] 操作数必须是可修改的左值

还有:

结果是更新后的操作数,也是一个左值(lvalue)


太棒了,谢谢。 - Ryan Dougherty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接