Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Обязательно ли NULL в Си является указателем?


Вопрос на основе обсуждения ответа про sizeof NULL.

Вот куски стандарта:


  An integer constant expression with the value 0, or such an expression cast t
type void *, is called a null pointer constant  
  
  NULL which expands to an implementation-defined null pointer constant


Кажется, что не запрещено вместо #define NULL ((void*)0) сделать просто #define NUL
0, как это сделано в плюсах. Тогда получается, что sizeof NULL равен либо sizeof (void*), либо sizeof (int) (в варианте sizeof 0).

Однако, @Vlad from Moscow утверждает, что NULL в Си обязан быть указателем.


  NULL в С определен как указатель.
  
  Ключевое значение в приведенной цитате имеют слова "cast to type void *".
  
  Здесь или имеет отношение не к приведению типов, а к виду выражения. И именно таким образом определяется NULL.


Так допустимо ли для Си (без плюсов) иметь?

#define NULL 0


И если допустимо, то почему в компиляторах используется

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif


вместо более простого варианта с нулём для обоих языков?
Ведь в си даже перегрузки функций не было, чтобы можно было что-то сломать.
    


Ответы

Ответ 1



Просмотрев внимательно стандарт C, я думаю, что вы правы. null pointer constant это либо целочисленное константное выражение со значением 0, либо такое выражение, приведенное к типу void *. Поэтому определение макроса NULL может быть в принципе различным, зависящим от реализаци компилятора. То есть нигде в стандарте C я не нашел, что макрос NULL обязан быть определен как ( void *)0 Я заглянул в документ Rationale for International Standard— Programming Languages— C и там нашел следующее (7.17 Common definitions ) 25 NULL can be defined as any null pointer constant. Thus existing code can retain definitions of NULL as 0 or 0L, but an implementation may also choose to define it as (void*)0. This latter form of definition is convenient on architectures where sizeof(void*) does not equal the size of any integer type. Так как null pointer constant преобразуется в выражениях в null pointer, а разме null pointer может быть не равен размеру ни одному целочисленному типу, то удобнее определять null pointer constant как ( void * )0 то есть сразу же приводить ее к типу указателя. В C++ от такого определения отказались, так как в отличии от C в C++ в связи с обеспечение безопасности типов нужно явное приведение указателя на void к типу указателя на конкретный объект. То есть если null pointer constant NULL будет определена в C++ как ( void *)0 то вам придется делать явное приведение указателей, как, например, int *p = ( int * )( void *)0; что, естественно, очень обременительно. Поэтому в C++ Отказались объявлять NULL в виде целочисленной константы, приведенной к типу void *.

Комментариев нет:

Отправить комментарий