Что такое "-1 [p]", когда p указывает на индекс массива (из int)?
Сегодня я наткнулся на загадку С, которая принесла мне новый сюрприз.
Я не думал, что -1 [p] в приведенном ниже примере скомпилируется, но это произошло. На самом деле, х в конечном итоге будет -3.
int x;
int array[] = {1, 2, 3};
int *p = &array[1];
x = -1[p]
Я искал в интернете что-то вроде -1 [указатель], но ничего не смог найти. Ладно, мне трудно ввести правильный поисковый запрос. Кто знает, почему -1 [p] компилируется, а X становится -3?
Ответы
Ответ 1
Я человек, который сделал эту "загадку" (см. мой пост в Twitter)
Так! Что случилось с -1 [p]?
ISO C фактически определяет [] как симметричный, то есть x[y]
совпадает с y[x]
, где x и y оба являются выражениями.
Наивно, мы можем прийти к выводу, что -1[p]
, следовательно, p[-1]
, и поэтому x = 1
,
Однако -1 на самом деле является оператором унарного минуса, примененного к константе 1, и унарный минус имеет более низкий приоритет, чем []
Итак, -1[p]
- это -(p[1])
, что приводит к -3.
Это также может привести к появлению в стиле фанк фрагментов, подобных этому:
sizeof(char)["abc"] /* yields 'b' */
Ответ 2
Первое, что нужно выяснить, это приоритет. А именно []
имеет более высокий приоритет, чем унарные операторы, поэтому -1[p]
равен -(1[p])
, а не (-1)[p]
. Итак, мы берем результат 1[p]
и отрицаем его.
x[y]
равен *(x+y)
, поэтому 1[p]
равен *(1+p)
, что равно *(p+1)
, что равно p[1]
.
Итак, мы берем элемент один после того, где указывает p
, то есть третий элемент в array
, то есть 3, и затем отрицаем его, что дает нам -3
.
Ответ 3
В соответствии со стандартом C (6.5.2 операторы Postfix) оператор нижнего индекса определяется следующим образом:
postfix-expression [ expression ]
Поэтому перед квадратными скобками должно быть выражение с постфиксом.
В этом выражении высказывание
x = -1[p];
здесь используется постфиксное выражение 1
(то есть одновременно первичное выражение), постфиксное выражение 1[p]
(то есть оператор индекса) и унарный оператор -
. Учтите, что при Компилятор разбивает программу на токены, а целочисленные константы считаются токенами без минуса. минус - это отдельный токен.
Таким образом, утверждение может быть переписано как
x = -( 1[p] );
потому что выражение постфикса имеет более высокий приоритет, чем унарное выражение.
Давайте сначала рассмотрим подфиксное выражение postfix 1[p]
Согласно стандарту C (6.5.2.1 Массив подписки)
2 Постфиксное выражение, за которым следует выражение в квадратных скобках [] является подписанным обозначением элемента объекта массива. Определение индекса оператора [] заключается в том, что E1 [E2] идентичен (* ((E1) + (E2))). Из-за правил преобразования, которые применяются к бинарный оператор +, если E1 является объектом массива (эквивалентно указателю к начальному элементу объекта массива) и E2 является целым числом, E1 [E2] обозначает E2-й элемент E1 (считая с нуля).
Таким образом, это подвыражение оценивается как *( ( 1 ) + ( p ) )
и совпадает с *( ( p ) + ( 1 ) ).
Таким образом, приведенное выше утверждение
x = -1[p];
эквивалентно
x = -p[1];
и выдаст -3
, потому что указатель p
указывает на второй элемент массива из-за оператора
int *p = &array[1];
а затем выражение p[1]
возвращает значение элемента после второго элемента массива. Затем применяется унарный оператор -
.
Ответ 4
Это
int array[] = {1, 2, 3};
выглядит как
array[0] array[1] array[2]
--------------------------
| 1 | 2 | 3 |
--------------------------
0x100 0x104 0x108 <-- lets assume 0x100 is base address of array
array
Дальше, когда тебе нравится
int *p = &array[1];
целочисленный указатель p
указывает на адрес array[1]
, т.е. 0x104
. Похоже,
array[0] array[1] array[2]
--------------------------
| 1 | 2 | 3 |
--------------------------
0x100 0x104 0x108 <-- lets assume 0x100 is base address of array
|
p holds 0x104
А когда тебе нравится
x = -1[p]
-1[p]
эквивалентно -(1[p])
, т.е. -(p[1])
. это выглядит как
-(p[1]) ==> -(*(p + 1*4)) /* p holds points to array[1] i.e 0x104 */
==> -(*(0x104 + 4))
==> -(*(0x108)) ==> value at 0x108 is 3
==> prints -3
Ответ 5
То, что здесь происходит, действительно интересно.
p [n] означает *(p+n)
. Вот почему вы видите 3, потому что "p" указывает на массив [1], который равен 2, а -p [1] интерпретируется как -(*(p+1))
, который является -3.