Почему NULL-указатели различаются по-разному на C и C ++?

В C NULL определяется как (void *)0 тогда как в C ++ оно равно 0 . Почему это так? В CI можно понять, что если NULL не является typecast для (void *) то компиляторы могут / не могут генерировать предупреждение. Кроме этого, есть ли причина?

Назад в C ++ 03, нулевой указатель был определен спецификацией ISO (§4.10 / 1) как

Константа нулевого указателя представляет собой целочисленное постоянное выражение (5.19) rvalue целочисленного типа, которое вычисляется до нуля.

Вот почему в C ++ вы можете написать

 int* ptr = 0; 

В C это правило аналогично, но немного отличается (§6.3.2.3 / 3):

Целочисленное постоянное выражение со значением 0 или такое выражение, отлитое от типа void * , называется константой нулевого указателя.55) Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указателем, равен гарантированно сравнивается неравномерно с указателем на любой объект или функцию.

Следовательно, оба

 int* ptr = 0; 

а также

 int* ptr = (void *)0 

являются законными. Тем не менее, я предполагаю, что void* cast здесь, так что утверждения вроде

 int x = NULL; 

выдает предупреждение о компиляторе в большинстве систем. В C ++ это не будет законным, потому что вы не можете неявно преобразовывать void* в другой тип указателя неявно без приведения. Например, это незаконно:

 int* ptr = (void*)0; // Legal C, illegal C++ 

Однако это приводит к проблемам, поскольку код

 int x = NULL; 

является законным C ++. Из-за этого и последующего путаницы (и другого случая, показанного ниже), поскольку C ++ 11, есть ключевое слово nullptr представляющее нулевой указатель:

 int* ptr = nullptr; 

У этого нет никаких проблем.

Другим преимуществом nullptr над 0 является то, что он лучше работает с системой типа C ++. Например, предположим, что у меня есть две функции:

 void DoSomething(int x); void DoSomething(char* x); 

Если я позвоню

 DoSomething(NULL); 

Это эквивалентно

 DoSomething(0); 

который вызывает DoSomething(int) вместо ожидаемого DoSomething(char*) . Однако, с помощью nullptr , я мог бы написать

 DoSomething(nullptr); 

И он будет вызывать функцию DoSomething(char*) как и ожидалось.

Точно так же предположим, что у меня есть vector и хочу, чтобы каждый элемент был нулевым указателем. Используя алгоритм std::fill , я могу попробовать написать

 std::fill(v.begin(), v.end(), NULL); 

Однако это не компилируется, поскольку система шаблонов рассматривает NULL как int а не указатель. Чтобы исправить это, мне пришлось бы написать

 std::fill(v.begin(), v.end(), (Object*)NULL); 

Это уродливо и несколько поражает цель системы шаблонов. Чтобы исправить это, я могу использовать nullptr :

 std::fill(v.begin(), v.end(), nullptr); 

И так как известно, что у std::nullptr_t есть тип, соответствующий нулевому указателю (в частности, std::nullptr_t ), это будет правильно скомпилировано.

Надеюсь это поможет!

В C NULL расширяется до определенной константой указателя нулевой указателя. Константа нулевого указателя представляет собой целочисленное константное выражение со значением 0 или такое выражение, отлитое от void* . Таким образом, реализация C может определять NULL либо как 0 либо как ((void*)0) .

В C ++ правила для констант нулевого указателя различны. В частности, ((void*)0) не является константой нулевого указателя C ++, поэтому реализация C ++ не может определить NULL таким образом.

Язык C был создан для упрощения программирования микропроцессоров. AC-указатель используется для хранения адреса данных в памяти. Необходимо было указать, что указатель не имеет действительного значения. Нулевой адрес был выбран, поскольку все микропроцессоры использовали этот адрес для загрузки. Поскольку он не может быть использован ни для чего другого, ноль был хорошим выбором для представления указателя без допустимого значения. C ++ обратно совместим с C, поэтому он унаследовал это соглашение.

Требование отливки нуля при использовании в качестве указателя – это только недавнее добавление. Более поздние поколения C хотели иметь более строгую (и, надеюсь, меньше ошибок), чтобы они стали более педантичными в отношении синтаксиса.

  • Указатели функций в Java
  • Объявление указателя на multidimensional array и выделение массива
  • Изменение строковых констант?
  • Когда следует использовать static_cast, dynamic_cast, const_cast и reinterpret_cast?
  • Go, X не реализует Y (... метод имеет приемник указателя)
  • Как передать объекты в функции на C ++?
  • Как сравнить две функции для равенства указателей в последней неделе?
  • Как использовать выражения указателя для доступа к элементам двумерного массива в C?
  • Почему массивы в C распадаются на указатели?
  • Динамическое распределение массива объектов
  • Сохранить int в массиве char?
  • Давайте будем гением компьютера.