在数组访问/下标中反转操作数的原因

时间:2017-02-18 19:30:03

标签: c arrays

在C中,可以反转数组下标的操作数,但仍然可以获得相同的结果。例如a[b] == b[a]。这是因为(根据C11 draft N1570, §6.5.2.1/2a[b](*((a)+(b)))相同,+是可交换的。有关更多信息,请参阅this question

是否存在某种情况(在C中,没有运算符重载),其中交换[]运算符的操作数不会导致结果相同运行时的价值?那么,ab是否存在a[b] != b[a]a[b] == a[b]? (假设程序编译并{{1}})

5 个答案:

答案 0 :(得分:4)

您似乎已经回答了自己的问题,并重申了为什么a[b]b[a]的含义相同。这种解释是正确的,直接建立在标准之上。主要警告是ab必须具有类型和值,以便评估a[b]已经定义了行为。只要是这种情况,两个表达式必须评估相同的事情。否则,C对这两个表达式是否评估相同的东西没什么好说的。

稍微不同的是,如果允许ab表示比变量名称和常量更复杂的表达式,那么可以选择它们评估整体条件表达式(a)[b] == (b)[a]具有未定义的行为,即使单独评估左侧和右侧子表达式已定义行为。例如,

char array[2] = "a";
int index = 0;
// undefined:
_Bool condition = array[index++] == (index++)[array];

但总的来说,无论C (a)[b] != (b)[a]a的类型,形式或值如何,C都不会将表达式b定义为真。

答案 1 :(得分:3)

好吧,如果你认为这是一个有效的反例:

    // Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }  

原因是下标运算符比间接运算符有higher precedence,因此xmlns:app="http://schemas.android.com/apk/res-auto" 等同于int *i; *i[i]; // does not compile i[*i]; // does compile ,这是无效的,因为下标运算符不能采用两种指针类型。 / p>

请注意,这些示例在实际执行时会产生未定义的行为。它只应该回答OP的问题。

答案 2 :(得分:0)

考虑以下计划:

<div class="container">
<div class="col-md-6">
    <div class="card">
      <div class="card-block">
        <h1 class="card-text good-review-score float-left">8.0</h1>
        <h4 class="card-title">Card on the Left 1</h4>
        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
      </div>
      <div class="card-footer">
        <p class="card-text text-right">Footer Text - Possible Link Out</p>
      </div>
    </div>
    <div class="card">
      <div class="card-block">
        <h1 class="card-text good-review-score float-left">8.0</h1>
        <h4 class="card-title">Card on the Left 2</h4>
        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
      </div>
      <div class="card-footer">
        <p class="card-text text-right">Footer Text - Possible Link Out</p>
      </div>
    </div>
</div>

<div class="col-md-6">
    <div class="card">
      <div class="card-block">
        <h1 class="card-text good-review-score float-left">8.0</h1>
        <h4 class="card-title">Card on the Right 1</h4>
        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
      </div>
      <div class="card-footer">
        <p class="card-text text-right">Footer Text - Possible Link Out</p>
      </div>
    </div>
    <div class="card">
      <div class="card-block">
        <h1 class="card-text good-review-score float-left">8.0</h1>
        <h4 class="card-title">Card on the Right 1</h4>
        <p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
      </div>
      <div class="card-footer">
        <p class="card-text text-right">Footer Text - Possible Link Out</p>
      </div>
    </div>
</div>

输出将是:

#include <stdio.h>

int x[2][2] = { { 1, 2 }, { 3, 4 } };
int *y = x[0];
int (*z)[2] = x;

#define a (*y)
#define b *z

int main(void) {
    printf("a[b] = %d\n", a[b]);
    printf("b[a] = %d\n", b[a]);
    return 0;
}

this answer一样,它利用a[b] = 2 b[a] = 3 优先于一元[]这一事实。所以:

  • *a[b](*y)[*z](1)[x[0]] = x[0][1]
  • 2b[a]*z[(*y)]*x[(1)] = x[1][0]

答案 3 :(得分:0)

是 - 对于宏体中的运算符优先级问题

在随意浏览WebKit源代码时,我发现an example作者有意将操作数转换为数组访问权。

#define ARRAY_SIZE(x) \
  ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

请注意,在两个地方,作者使用0[x]而不是更传统的x[0]。我认为,其原因在于这种用法发生在宏内,而不是原始代码中。由于x实际上是宏的参数,因此其值将以文本方式替换为宏体。这样做的结果是x不必是单个标识符,但可能在中缀表达式中。在这种情况下,运算符优先级问题可能会蔓延。例如,这种用法:

int a[] = {0, 1};
ARRAY_SIZE(a); // Expands as 0[a]

int b[] = {0, 1};
ARRAY_SIZE(b+1); // Expands as 0[b+1]

如果操作数相反,则对ARRAY_SIZE的两次调用将分别扩展为a[0]b+1[0]。前者按预期工作,但后者可能是分段错误,因为它等同于b+(1[0])

实际上,通过将操作数反转为数组访问,作者已经避免了主动将其宏参数括起来的需要。这可能不是一个令人难以置信的强大用法,但它在可操作性(可能更大)的可读性方面逆转操作数是一个很小的好处。

答案 4 :(得分:-1)

int *i; *i[i]; // like number[pointer] i[*i]; // does like pointer[number]

中的

pointer[number]是您访问数组中成员的方式。

除非您将i[*i]更改为int *i;

,否则int *i; *i=value;将无法编译

是一个数字时。