【问题标题】:What is '-1[p]' when p points to an array (of int) index? [duplicate]当 p 指向一个数组(int)索引时,'-1[p]' 是什么? [复制]
【发布时间】:2019-12-21 06:47:23
【问题描述】:

今天我偶然发现了一个 C 谜语,给我带来了新的惊喜。

我认为下面示例中的 -1[p] 不会编译,但它确实可以编译。事实上,x 最终是 -3。

    int x;
    int array[] = {1, 2, 3};
    int *p = &array[1];
    x = -1[p]

我在互联网上搜索了类似 -1[pointer] 的东西,但找不到任何东西。好吧,我承认很难输入正确的搜索查询。谁知道为什么 -1[p] 编译后 X 变成 -3?

【问题讨论】:

  • -(p[1])-(array[2])
  • 这个谜语有两个层次:要理解它,首先你必须知道a[5] == 5[a]。但是,如果您还没有记住 C 的不太直观的优先规则,或者如果您不记得 C 将 -1 视为一元减号运算符的应用程序(而不是将其视为单个标记和本质上负常数),您可能会误以为-1[p]p[-1] 相同,而不是-(p[1])
  • 当然它的绑定比索引低,否则看起来理智的-p[1]会试图否定一个指针......
  • @EugeneSh。我也正要投票给a[5] == 5[a] 一个作为骗子,但它实际上只涵盖了这个问题的一半。我想说这里令人惊讶的优先级同样重要。
  • @SteveSummit 我不确定为什么优先级如此令人惊讶并且值得一整个 5 个答案的问题。是的,这可能有点令人困惑,但这是一个非常基本的事情,尤其是考虑到代码执行的结果..

标签: c arrays pointers unary-operator postfix-operator


【解决方案1】:

我是制造这个“谜语”的人(见my Twitter post

所以! -1[p] 怎么了?

ISO C 实际上将 [] 定义为对称的,意思是 x[y]y[x] 相同,其中 x 和 y 都是表达式。

天真地,我们可以得出结论,-1[p] 因此是p[-1]x = 1, 然而,-1实际上是应用于常量1的一元减号运算符,而一元减号的优先级低于[]

所以,-1[p]-(p[1]),产生 -3。

这也可能导致像下面这样看起来很时髦的 sn-ps:

sizeof(char)["abc"] /* yields 'b' */

【讨论】:

    【解决方案2】:

    首先要弄清楚的是优先级。即[] 的优先级高于一元运算符,因此-1[p] 等于-(1[p]),而不是(-1)[p]。所以我们将1[p] 的结果取反。

    x[y]等于*(x+y),所以1[p]等于*(1+p),等于*(p+1),等于p[1]

    所以我们在p 指向的位置之后取元素,所以array 的第三个元素,即3,然后取反,得到-3

    【讨论】:

      【解决方案3】:

      根据 C 标准(6.5.2 后缀运算符),下标运算符定义如下

      postfix-expression [ expression ]
      

      所以在方括号之前应该有一个后缀表达式。

      在这个表达式语句中

      x = -1[p];
      

      这里使用了后缀表达式1(即同时是一个主表达式)、后缀表达式1[p](即下标运算符)和一元运算符-编译器将程序拆分为标记,然后整数常量被视为标记本身,没有减号。减号是一个单独的标记。

      所以语句可以改写为

      x = -( 1[p] );
      

      因为后缀表达式的优先级高于一元表达式。

      让我们首先考虑后缀子表达式1[p]

      根据 C 标准(6.5.2.1 数组下标)

      2 后缀表达式后跟方括号 [] 中的表达式 是数组对象元素的下标名称。这 下标运算符 [] 的定义是 E1[E2] 等同于 (*((E1)+(E2)))。由于适用于 二进制 + 运算符,如果 E1 是一个数组对象(相当于一个指针 到数组对象的初始元素)并且 E2 是一个整数, E1[E2] 表示 E1 的第 E2 个元素(从零开始计数)。

      所以这个子表达式的计算结果类似于 *( ( 1 ) + ( p ) ) 并且与 *( ( p ) + ( 1 ) ). 相同

      所以上面的说法

      x = -1[p];
      

      等价于

      x = -p[1];
      

      并且会产生-3,因为指针p由于语句指向数组的第二个元素

      int *p = &array[1];
      

      然后表达式p[1] 产生数组第二个元素之后的元素的值。然后应用一元运算符-

      【讨论】:

        【解决方案4】:

        这个

        int array[] = {1, 2, 3};
        

        看起来像

        array[0]   array[1]  array[2]
         --------------------------
        |     1   |    2    |   3  | 
         --------------------------
         0x100     0x104     0x108   <-- lets assume 0x100 is base address of array
        array
        

        喜欢的时候下一个

        int *p = &array[1];
        

        整数指针p指向array[1]的地址,即0x104。好像

        array[0]   array[1]  array[2]
         --------------------------
        |     1   |    2    |   3  | 
         --------------------------
         0x100     0x104     0x108   <-- lets assume 0x100 is base address of array
                     |
                    p holds 0x104
        

        当你喜欢时

        x = -1[p]
        

        -1[p] 等价于-(1[p]),即-(p[1])。看起来像

        -(p[1]) ==> -(*(p + 1*4)) /* p holds points to array[1] i.e 0x104 */
                ==> -(*(0x104 + 4))
                ==> -(*(0x108)) ==> value at 0x108 is 3
                ==> prints -3
        

        【讨论】:

          【解决方案5】:

          这里发生的事情真的很有趣。

          p[n] 表示*(p+n)。这就是您看到 3 的原因,因为“p”指向数组 [1],即 2,而 -p[1] 被解释为 -(*(p+1)),即 -3。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-14
            • 1970-01-01
            • 1970-01-01
            • 2012-07-03
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多