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