Согласно ответам в, "Почему вычитают нулевого указателя в offsetof ()?" (и мое чтение K&R), стандарт C не требует этого (size_t)((char *)0) == 0
. Однако, я никогда не видел ситуации, где кастинг нулевого указателя к целому типу оценивает к чему-либо еще.
Если существует компилятор или сценарий где (size_t)((char *)0) != 0
, что это?
Ну, как вы знаете, физическое представление null указатель данного типа не обязательно является битовой комбинацией с нулевым значением. Когда вы принудительно преобразуете значение указателя (любого указателя) в целочисленный тип, результат определяется реализацией, но обычно (и это намерение) числовое значение указателя - числовой адрес - остается неизменным, если это возможно. Это означает, что если на данной платформе нулевой указатель типа char *
представлен шаблоном 0xBAADF00D
(например), приведенное выше выражение будет оцениваться как 0xBAADF00D
, а не до нуля. Конечно, для этого вам понадобится платформа с ненулевыми нулевыми указателями. Я лично никогда не работал с такими платформами, хотя слышал о ряде реальных платформ, подобных этой (например, в сфере встроенных платформ это не является чем-то необычным).
Кроме того, в качестве дополнительного примечания, значения нулевого указателя разных типов могут иметь различное физическое представление, что означает, что теоретически вы можете получить разные значения из (size_t) ((int *) 0)
, (size_t) ((char *) 0)
и (size_t) ((double *) 0)
. Но это была бы довольно экзотическая ситуация, хотя вполне возможная с точки зрения абстрактного языка C.
P.S. Прочтите здесь (C FAQ), чтобы узнать о некоторых примерах реальных платформ с ненулевыми нулевыми указателями.
Это не относится к char *
или даже к C, но класс интеллектуального указателя, который индексирует массив, может представлять NULL
как -1
, потому что 0
является допустимым индексом массива.
Учитывая идиому memset (my_new_struct, 0, sizeof my_new_struct);
, даже система, ориентированная на отладку, вряд ли нарушит эту идентичность.
Единственное, что стандарт C требует от представления времени выполнения нулевого указателя, это (6.3.2.3/3 «Указатели»):
... результирующий указатель, называемый нулевым указателем, гарантированно не равен указателю на любой объект или функцию. Преобразование нулевого указателя в другой тип указателя дает нулевой указатель этого типа.
Любые два нулевых указателя должны сравниваться как равные.
Однако ваш вопрос интересный. Лично мне неизвестна платформа, которая не использует значение времени выполнения 0 для представления нулевого указателя. Однако стандарт этого не требует, поэтому, если вы можете избежать допущения в своем коде, почему бы и нет?
Меня также заинтересует любой, кто знает систему, которая использует ненулевое значение времени выполнения для нулевой указатель.
Стандарт C99 говорит, что когда вы конвертируете целочисленное значение 0
в указатель, оно становится NULL-указателем. Итак, ((char *) 0)
является указателем NULL. НУЛЕВОЙ указатель не обязательно должен иметь фактическое двоичное представление 0
. Это может быть, например, 0x12345678
.
Стандарт C также утверждает, что при преобразовании указателя NULL в целочисленную константу результат "определяется реализацией". На самом деле компиляторы просто приводят числовое значение указателя к соответствующему целочисленному значению, как сказал AndreyT. Таким образом, в приведенном выше примере целочисленное значение может оказаться 0x12345678
, хотя технически это может быть что угодно (т. Е. Компилятору разрешено сказать «преобразование NULL-указателя обратно в целочисленное значение приводит к значение 0xDEADBEEF
"). Обратите внимание, что это означает, что даже на платформах, где указатель NULL имеет значение 0
, компилятор может преобразовать его в произвольное целочисленное значение при преобразовании. На самом деле, однако, никакие компиляторы этого не делают, потому что это было бы довольно безумно.
Итак, да, стандарт C позволяет многое. В действительности, любая платформа, на которой вы, вероятно, будете работать, будет представлять NULL-указатель как 0
, а преобразование NULL-указателя в целочисленное значение приведет к 0
. Посмотрите здесь (раздел 1.14) для списка некоторых исключений (неясных) архитектур, которые не используют 0
для NULL-указателя.