Разве (size_t) ((char *) 0) никогда не оценивается как 0? - PullRequest
5 голосов
/ 06 апреля 2010

Согласно ответам в «Зачем вычитать нулевой указатель в offsetof ()?» (и мое чтение K & R), стандарт C не требует, чтобы (size_t)((char *)0) == 0. Тем не менее, я никогда не видел ситуации, когда приведение нулевого указателя к целочисленному типу приводит к чему-либо еще.

Если есть компилятор или сценарий, где (size_t)((char *)0) != 0, что это?

Ответы [ 4 ]

4 голосов
/ 06 апреля 2010

Ну, как вы знаете, физическое представление нулевого указателя данного типа не обязательно является шаблоном с нулевыми битами. Когда вы принудительно преобразуете значение указателя (любого указателя) в целочисленный тип, результат определяется реализацией, но обычно (и это намерение) числовое значение указателя - числовой адрес - остается неизменным, если возможно. Это означает, что если на данной платформе нулевой указатель типа char * представлен шаблоном 0xBAADF00D (например), приведенное выше выражение будет иметь значение 0xBAADF00D, а не ноль. Конечно, для этого вам понадобится платформа с ненулевыми нулевыми указателями. Лично я никогда не работал с такими платформами, хотя я слышал о ряде реальных платформ, подобных этому (например, в сфере встроенных платформ это не является чем-то необычным).

Кроме того, в качестве дополнительного примечания, значения нулевого указателя разных типов могут иметь разные физические представления, что означает, что в теории вы можете получить разные значения из (size_t) ((int *) 0), (size_t) ((char *) 0) и (size_t) ((double *) 0). Но это была бы довольно экзотическая ситуация, хотя и вполне возможная с точки зрения абстрактного языка Си.

P.S. Прочитайте здесь (C FAQ), чтобы найти примеры реальных платформ с ненулевыми нулевыми указателями.

1 голос
/ 06 апреля 2010

Стандарт 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.

1 голос
/ 06 апреля 2010

Единственное, что стандарт C требует от представления времени выполнения нулевого указателя, это (6.3.2.3/3 «Указатели»):

... результирующий указатель, называемый нулевым указателем, гарантированно сравнивается с указателем на любой объект или функцию. Преобразование нулевого указателя в другой тип указателя дает нулевой указатель этого типа.

Любые два нулевых указателя должны сравниваться равными.

Хотя ваш вопрос интересный. Лично я не знаю о платформе, которая не использует значение времени выполнения 0 для представления нулевого указателя. Однако стандарт не требует этого, поэтому, если вы можете избежать предположения в вашем коде, почему бы и нет?

Мне также был бы интересен любой, кто знает о системе, которая использует ненулевое значение времени выполнения для нулевого указателя.

0 голосов
/ 06 апреля 2010

Это не относится к char* или даже к C, но класс интеллектуальных указателей, который индексирует в массив, может выбрать NULL как -1, поскольку 0 является допустимым индексом массива.

Учитывая идиому memset( my_new_struct, 0, sizeof my_new_struct );, даже система, ориентированная на отладку, вряд ли сломает эту идентичность.

...