对于数组,为什么会出现[5] == 5 [a]?
正如Joel在Stack Overflow podcast#34中指出的那样,在C编程语言(aka:K&R)中,提到了C: a[5] == 5[a]
乔尔说这是因为指针算术,但我仍然不明白。 为什么a[5] == 5[a]
?
C标准定义[]
运算符如下:
a[b] == *(a + b)
因此a[5]
将评估为:
*(a + 5)
和5[a]
将评估为:
*(5 + a)
a
是指向数组的第一个元素的指针。 a[5]
是距a
更远的5个元素的值,与*(a + 5)
,并且从小学数学我们知道这些数学是相等的(加法是可交换的)。
因为数组访问是根据指针定义的。 a[i]
被定义为意味着*(a + i)
,它是可交换的。
我认为其他答案错过了某些东西。
是的, p[i]
在定义上相当于*(p+i)
,它(因为加法是可交换的)相当于*(i+p)
,它(同样是由[]
运算符定义的)是等价的到i[p]
。
(在array[i]
,数组名称被隐式转换为指向数组第一个元素的指针。)
但是在这种情况下加法的交换性并不是那么明显。
当两个操作数具有相同类型时,或者甚至是提升为常见类型的不同数值类型时,交换性都非常合理: x + y == y + x
。
但在这种情况下,我们正在专门讨论指针算术,其中一个操作数是指针,另一个是整数。 (整数+整数是不同的操作,而指针+指针是无稽之谈。)
C标准对+
运营商的描述(N1570 6.5.6)说:
另外,两个操作数都应该有算术类型,或者一个操作数应该是一个指向完整对象类型的指针,另一个应该是整数类型。
它可以很容易地说:
另外,两个操作数都应具有算术类型,或者左操作数应该是指向完整对象类型的指针,右操作数应该具有整数类型。
在这种情况下, i + p
和i[p]
都是非法的。
用C ++术语来说,我们确实有两套重载的+
运算符,可以粗略地描述为:
pointer operator+(pointer p, integer i);
和
pointer operator+(integer i, pointer p);
其中只有第一个是真正必要的。
那么为什么这样呢?
C ++继承了C语言中的这个定义,它从B获得(数组索引的交换性在1972年用户参考文献中明确提到),它从BCPL(1967年的手册)中得到它,这很可能是从它较早的语言(CPL?Algol?)。
因此,数组索引是以加法的形式定义的,而且,除了一个指针和一个整数之外,它还是可交换的,可以追溯到几十年前的C语言的祖先语言。
这些语言的类型要比现代C语言少得多。 特别是,指针和整数之间的区别经常被忽略。 (早期的C程序员有时在将unsigned
关键字添加到语言之前使用指针作为无符号整数)。因此,由于操作数具有不同类型而使得添加不可交换,所以这些语言的设计者可能不会出现这种想法。 如果用户想要添加两个“东西”,无论这些“东西”是整数,指针还是别的东西,它都不符合该语言来防止它。
多年来,任何对该规则的改变都会破坏现有的代码(虽然1989年的ANSI C标准可能是一个很好的机会)。
将C和/或C ++更改为需要将指针放在左侧并且右侧的整数可能会破坏一些现有的代码,但不会损失真正的表现力。
所以现在我们有arr[3]
和3[arr]
意思完全一样的东西,尽管后一种形式不应该出现在IOCCC之外。