Небольшое уточнение по этой теме.
Прежде всего, это неопределенное поведение в соответствии со стандартом C по причинам, указанным StoryTeller:
Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, при оценке не должно быть переполнения; в противном случае поведение не определено.
Поскольку литерал с нулевой константой, преобразованный в любой тип указателя, распадается на константу с нулевым указателем, которая не указывает на какую-либо непрерывную область памяти, поведение не определено.
Однако , выполнение арифметических операций с нулевыми указателями для извлечения смещений не является новым, реализация C макроса offsetof
использует его:
#define offsetof(st, m) ((size_t)&(((st *)0)->m))
И выполнение арифметических операций с указателями также часто:
int *end = (int *)0 + array_size;
Эта строка практически совпадает с записью:
int *end = (int *)(sizeof(int) * array_size);
Я полагаю, что вычисление смещения определяется реализацией, поскольку компилятор «мог» разыменовывать такие указатели для получения фактического смещения памяти, что, конечно, очень маловероятно, но все же возможно.
Также обратите внимание, что это предупреждение для арифметики с нулевым указателем относится к Clang 6.0. GCC не запускает его даже при -fsanitize=undefined
.