我认为其他答案缺少一些东西。
是的,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继承了这个定义,而C则从B得到了它(1972年用户参考B明确提到了数组索引的可交换性),而BCPL则得到了它。(1967年手册)得到的,甚至可能从早期语言(CPL?Algol?)。
因此,数组索引是根据加法定义的,并且即使是指针和整数的加法也是可交换的,这种想法可以追溯到几十年前的C祖先语言。
与现代C语言相比,这些语言的强类型要少得多。特别是,指针和整数之间的区别通常被忽略。(在将unsigned
关键字添加到语言之前,早期的C程序员有时将指针用作无符号整数。)因此,由于操作数的类型不同,使这些语言的设计人员可能不会想到使加法运算不可交换。如果用户想添加两个“事物”,无论这些“事物”是整数,指针还是其他事物,都无法阻止该语言。
多年来,对该规则的任何更改都会破坏现有代码(尽管1989年ANSI C标准可能是一个很好的机会)。
更改C和/或C ++要求将指针放在左侧,将整数放在右侧可能会破坏某些现有代码,但不会损失实际的表达能力。
因此,现在我们拥有arr[3]
和3[arr]
意义完全相同的东西,尽管后者永远不应出现在IOCCC之外。