Во-первых, небезопасно использовать %d
для печати различий указателей, имеющих тип ptrdiff_t
(это версия со знаком size_t
).
Игнорируя это, у вас есть следующие объявления:
char arr[5][7][6];
char (*p)[5][7][6] = &arr;
При вычитании двух указателей результат делится на размер цели (т. Е. Значение, обратное тому, что происходит при добавлении целого числа к указателю, и в этом случае целое число масштабируется с помощьюsize).
Для первого примера:
(&arr + 1) - &arr
Здесь оба типа &arr
и &arr + 1
имеют тип char (*)[5][7][6]
, поэтому размер, на который они указывают, равен sizeof(char [5][7][6])
,Добавление указателя умножает 1
на этот размер, а вычитание указателя делит разницу на этот размер, компенсируя ее.Таким образом, результат равен 1
, независимо от целевого размера.
Для второго примера:
(char *)(&arr + 1) - (char *)&arr
Здесь сложение указателя снова умножает 1 на sizeof(char [5][7][6])
, что составляет sizeof(char)*5*7*6
, то есть 1*5*7*6
, что 210
.Но вычитание делится на sizeof(char)
, что составляет 1
.Таким образом, результат равен 210
.
Для третьего примера:
(unsigned)(arr + 1) - (unsigned)arr
Эффект приведения unsigned
аналогичен эффекту приведения char *
в предыдущемпример.Тем не менее, в этом два указателя arr
и arr + 1
.В этом контексте типы массивов «распадаются» на типы указателей char (*)[7][6]
.Следовательно, размер указателя цели равен sizeof(char)*7*6
, т.е. 1*7*6
, что составляет 42
.Таким образом, результат равен 42
.
Наконец, для последнего примера:
(unsigned)(p + 1) - (unsigned)p)
Оба типа p
и p + 1
имеют тип char (*)[5][7][6]
, поэтому целевой размер равен 210
.Повторное приведение unsigned
приводит к прямому вычитанию адреса без деления на результат.Таким образом, результат 210
.