Вопрос на основе обсуждения ответа про sizeof NULL. Вот куски стандарта: An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant NULL which expands to an implementation-defined null pointer constant Кажется, что не запрещено вместо #define NULL ((void*)0) сделать просто #define NULL 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 вместо более простого варианта с нулём для обоих языков? Ведь в си даже перегрузки функций не было, чтобы можно было что-то сломать.
Ответ Просмотрев внимательно стандарт 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 *.