正如 Joel 在Stack Overflow 播客#34 中指出的那样,在C 编程语言 (又名: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 年用户参考 B 中明确提到了数组索引的交换性)得到它,它从BCPL (1967 年的手册)得到它,它甚至可以从它获得它早期的语言(CPL?Algol?)。
因此,数组索引是根据加法来定义的,并且即使是指针和整数,这种加法也是可交换的,可以追溯到 C 的祖先语言几十年。
这些语言的类型远不如现代 C 语言。特别是,指针和整数之间的区别经常被忽略。 (在将unsigned
关键字添加到语言之前,早期的 C 程序员有时使用指针作为无符号整数。)因此,由于操作数是不同类型而使得加法不可交换的想法可能不会发生在那些语言的设计者身上。 。如果用户想要添加两个 “东西”,无论这些 “东西” 是整数,指针还是其他东西,都不能用语言来阻止它。
多年来,对该规则的任何更改都会破坏现有代码(尽管 1989 ANSI C 标准可能是一个很好的机会)。
改变 C 和 / 或 C ++ 要求将指针放在左边,而整数放在右边可能会破坏一些现有的代码,但不会损失真正的表达能力。
所以现在我们有arr[3]
和3[arr]
意思完全相同,尽管后一种形式永远不会出现在IOCCC之外。