在C中,可以反转数组下标的操作数,但仍然可以获得相同的结果。例如a[b] == b[a]
。这是因为(根据C11 draft N1570, §6.5.2.1/2)a[b]
与(*((a)+(b)))
相同,+
是可交换的。有关更多信息,请参阅this question。
是否存在某种情况(在C中,没有运算符重载),其中交换[]
运算符的操作数不会导致结果相同运行时的价值?那么,a
和b
是否存在a[b] != b[a]
和a[b] == a[b]
? (假设程序编译并{{1}})
答案 0 :(得分:4)
您似乎已经回答了自己的问题,并重申了为什么a[b]
与b[a]
的含义相同。这种解释是正确的,直接建立在标准之上。主要警告是a
和b
必须具有类型和值,以便评估a[b]
已经定义了行为。只要是这种情况,两个表达式必须评估相同的事情。否则,C对这两个表达式是否评估相同的东西没什么好说的。
稍微不同的是,如果允许a
和b
表示比变量名称和常量更复杂的表达式,那么可以选择它们评估整体条件表达式(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]
2
→b[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;
将无法编译
当值是一个数字时。