“++i++”为什么是无效的,而“(++i)++”是有效的?

14

让我们考虑以下代码:

int main() {
    int i = 2;
    int b = ++i++;
    return 3;
}

编译以下内容时出现错误:

<source>: In function 'int main()':

<source>:3:16: error: lvalue required as increment operand

    3 |     int b = ++i++;

      |                ^~

我认为这很公平。后缀递增比前缀递增的优先级更高,因此代码解析为int b = ++(i++);并且i是一个rvalue。因此出现了错误。

现在让我们考虑使用括号来覆盖默认优先级的这个变体:

int main() {
    int i = 2;
    int b = (++i)++;
    return 3;
}

这段代码可以编译并返回3。单独来看,这对我来说听起来还算合理,但它似乎与第一段代码相矛盾。

问题是:为什么(++i)lvalue,而i不是?

谢谢!

更新:上面显示的错误消息来自gcc(x86-64 9.2)。以下是精确的呈现: 使用gcc出现的错误

Clang x86-64 9.0.0的错误消息有所不同: 使用clang出现的错误

<source>:3:13: error: expression is not assignable

    int b = ++i++;

            ^ ~~~

使用GCC编译器,你会发现问题出在后缀运算符上,然后你可以想知道为什么++i是可以的而i不行,因此有了我的这个问题。而使用Clang编译器,更清楚地表明问题出在前缀运算符上。


这最初被标记为C,但它绝对不是有效的C。 - Antti Haapala -- Слава Україні
真的很抱歉!我假设在C语言中行为是相同的... - Bktero
3个回答

23

i++i都是左值,但i++是一个右值。

++(i++)是无效的,因为前缀++被应用于i++,而后者是一个右值。但是(++i)++是可以的,因为++i是一个左值。

请注意,在C语言中,情况不同;i++++i都是右值。 (这是一个例子,说明人们应该停止假设C和C ++具有相同的规则。人们将这些假设插入到他们的问题中,必须被驳斥。)


4
这个声明
int b = ++i++;

等同于

int b = ++( i++ );

后置递增运算符会在递增之前返回操作数的值。
来自C++ 17标准(8.2.6递增和递减):
1.后缀++表达式的值是其操作数的值...结果是一个prvalue。
而一元递增运算符在递增后返回lvalue。因此,这个声明:
int b = (++i)++;

是有效的。例如,您可以编写

int b = (++++++++i)++;

根据C++ 17标准(8.3.2 增量和减量运算符),前缀 ++ 的操作数将增加1。该操作数应为可修改的左值。操作数的类型应该是算术类型而非cv布尔类型,或者是指向完全定义的对象类型的指针。更新后的操作数是一个左值,如果操作数是位域,则它是一个位域。

需要注意,在C语言中这两个运算符返回的是值而非左值。因此在C语言中,以下声明:

int b = (++i)++;

无效。


3
所以代码被解析为 int b = ++(i++); 并且 i 是一个 lvalue,不是 rvalue。i++ 是一个 rvalue(具体来说是 prvalue)。

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