【问题标题】:Why isn't arr[-2] equivalent to -2[arr]?为什么 arr[-2] 不等于 -2[arr]?
【发布时间】:2017-11-06 01:26:50
【问题描述】:
#include <iostream>
using namespace std;

int main() 
{
    int arr[3] = { 10, 20, 30 };
    cout << arr[-2] << endl;
    cout << -2[arr] << endl;        
    return 0;
}

输出:

4196160
-30

此处arr[-2] 超出范围且无效,导致未定义行为。 但是-2[arr] 的计算结果为-30。为什么?

arr[-2]不等于-2[arr]吗?

【问题讨论】:

  • 只是为了使问题正确(删除UB),您可以定义int *arr2 = arr + 2并将arr2与-2一起使用。
  • 我无法摆脱这种感觉,您应该能够通过查看输出来轻松自己解决这个问题。好吧,至少你问了一个很好的问题。
  • 这个问题没有显示出任何研究成果(从投反对票的原因)
  • 虽然 Chris 的回答是正确的,但假设它 等同于 (-2)[arr]:为什么您认为在这种情况下打印 -30 与行为未定义?
  • @LyingOnTheSky 这是 undefined 行为。 arr[-2] 完全可以接受同时打印4196160-30,清除数组,然后将 cout::operator

标签: c++ arrays undefined-behavior


【解决方案1】:

-2[arr] 被解析为-(2[arr])。在 C 中(在 C++ 中,忽略重载),X[Y] 的定义是 *(X+Y)(参见this question 中的更多讨论),这意味着2[arr] 等于arr[2]

【讨论】:

  • 你只需要记住我猜的运算符优先规则。或者只是不要使用这种令人困惑的结构......
  • @DeiDei 无论如何,做(-2)[arr] 并不是一个好习惯。 ;)
  • C/C++ 的操作顺序很简单:*+ 之前,对于其他所有内容,请使用括号。
  • @Yakk:恕我直言,垃圾。你真的会写(arr[2]) + (arr[3])吗? (因为您不记得 + 的优先级是否高于或低于 [])。或((ptr-&gt;a)[2]) + ((ptr-&gt;a)[0]。我还认为,在与||&amp;&amp; 结合使用时,在比较中加上括号是没有意义的(但我接受这更有争议)。
  • @MartinBonner 很确定那是个玩笑
【解决方案2】:

编译器解析这个表达式

-2

喜欢

unary_minus decimal_integer_literal

也就是说整数字面量的定义不包括符号。

依次表达

2[arr]

被编译器解析为后缀表达式。

后缀表达式的优先级高于一元表达式。因此这个表达式

-2[arr]

等价于

- ( 2[arr] )

所以一元减号应用于后缀表达式2[arr]返回的左值。

另一方面,如果你写了

int n = -2;

然后

n[arr]

那么这个表达式就等价于

arr[-2]

【讨论】:

  • 这在 C++ 中怎么可能?从什么时候a[b] 等于b[a],我从来不知道为什么要使用它?我在哪里可以读到这个,因为我无法确定它是如何被调用的
  • @Gizmo 虽然与其他地方的某些陈述相反,数组确实作为 C 中的单独数据结构存在,但访问 inin 数组中的数据的方法基本上仅限于使用它们的衰减到指针的特征。因此,当您在大多数情况下引用 a 时,您的真正意思是“指向数组 a 的第一个元素的指针”。所以要得到你想要的实际元素*a。要获得第二个元素,您需要*(a+1)。这是一个相当丑陋和笨拙的结构,因此 C 提供了a[1] 作为上述语法糖。因为a+1 == 1+a, 1[a] == a[1]。在 C++ 中,您可以重载它以使其更加混乱。
  • 啊,这就是它的来源,还找到了this,它很好地解释了它并最终导致this,这是一个更好的阅读
  • @Gizmo 这个问题有更多信息With arrays, why is it the case that a[5] == 5[a]?
【解决方案3】:

-2[arr] 等价于-(2[arr]),即等价于-arr[2]。但是,(-2)[arr] 等价于 arr[-2]

这是因为E1[E2] is identical to (*((E1)+(E2)))

【讨论】:

  • 我认为A[B](*A+(B)) 相同,而不是(*(A)+(B))。否则,-2[arr] 将等同于 (*(-2)+(arr)),但事实并非如此。
  • @wizzwizz4 答案是正确的。 -2[arr] 不是A[B] 的形式,因为有优先级。当它解析为-(2[arr]) 时,括号会破坏您的A,并且您的论点不适用。如果确实如此,那么您可以声称2*3+4 等于2*4+3,因为3+4 等于4+3
  • @jamesqf @jamesqf 因为没有语法错误:-2[arr]定义-(*((2)+(arr))),即-(*(arr-2))(,也就是定义arr[-2]) .然而,虽然x[arr] 是一个合法的表达方式,但通常我们只写arr[x]
  • @SunQingyao 您的ie后面的两个陈述是错误的。应该是 -(*(arr+2)) 即 -arr[2]。
  • @SunQingyao:这些定义似乎表明somestruct -&gt; arr[n] 应该等同于(&amp;someStruct-&gt;arr[0])[n],但gcc 似乎对它们有不同的看法。我不确定标准中的哪些内容可以证明这种区别是合理的。
【解决方案4】:

根本问题在于运算符优先级。在 C++ 中,[],即下标运算符比- unary_minus 运算符拥有更多优先级(有点类似于优先级)。

所以当一个人写作时,

arr[-2]

编译器首先执行 arr[] 然后 - ,但 unary_minus 包含在 [-2] 的范围内,因此表达式被分解在一起。

在,

-2[arr]

同样的事情发生了,但是编译器首先执行2[],然后是-运算符,所以它最终是 -(2[arr])不是(-2)[arr]

你对这个概念的理解, arr[i] i[arr]*(i+arr) 都一样是正确的。它们都是等价的表达式。

如果你想这样写,写成(-2)[arr]。你肯定会得到相同的值。

查看此内容以供将来参考:http://en.cppreference.com/w/cpp/language/operator_precedence

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-05
    • 2020-07-03
    • 2020-01-26
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    相关资源
    最近更新 更多