Я думаю, что что-то упускается другими ответами.
Да, p[i]
по определению эквивалентно *(p+i)
, что (поскольку сложение является коммутативным) эквивалентно *(i+p)
, что (опять же, по определению оператора []
) эквивалентно i[p]
.
(А в array[i]
имя массива неявно преобразуется в указатель на первый элемент массива.)
Но в этом случае коммутативность сложения не так уж очевидна.
Когда оба операнда имеют одинаковый тип или даже разные числовые типы, которые переводятся в общий тип, коммутативность имеет смысл: x + y == y + x
.
Но в данном случае мы говорим конкретно об арифметике указателей, где один операнд является указателем, а другой - целым числом. (Целое + целое - это другая операция, а указатель + указатель - это нонсенс.)
Описание стандарта * оператора +
( 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 иногда использовали указатели как целые числа без знака до того, как ключевое слово unsigned
было добавлено в язык.) Поэтому идея сделать добавление некоммутативной, поскольку операнды имеют разные типы, вероятно, не возникла бы у разработчиков эти языки. Если пользователь хотел добавить две «вещи», будь то эти «вещи», являются целыми числами, указателями или чем-то еще, язык не мог предотвратить это.
И с годами любое изменение в этом правиле нарушило бы существующий код (хотя стандарт ANSI C 1989 года мог бы стать хорошей возможностью).
Изменение C и / или C ++, требующее размещения указателя слева и целого числа справа, может нарушить некоторый существующий код, но при этом не будет потеря реальной выразительной силы.
Так что теперь у нас есть arr[3]
и 3[arr]
, означающие абсолютно одно и то же, хотя последняя форма никогда не должна появляться за пределами IOCCC .