Вопрос в том, почему это разрешено в соответствии со стандартом
Потому что должен быть способ express нулевого указателя. Разработчик языка C выбрал, что 0 будет нулевым. Разработчик C ++ решил быть совместимым с C, и поэтому 0 является константой нулевого указателя.
Позже в C ++ 11 nullptr
было введено как новое ключевое слово. Интегральные константы нулевого указателя не могут быть заменены, потому что это нарушит обратную совместимость, поэтому эти различные способы express null сосуществуют. Нет причин использовать 0 в качестве нулевого указателя, если вам не нужно поддерживать системы до C ++ 11.
и, в частности, что разрешено
Standard говорит (последний черновик):
[conv.ptr] Константа нулевого указателя - это целочисленный литерал ([lex.icon]) с нулевым значением или prvalue типа std :: nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является значение нулевого указателя этого типа ([basi c .compound]), которое отличается от любого другого значения указателя на объект или типа указателя на функцию. Такое преобразование называется преобразованием нулевого указателя. Два значения нулевого указателя одного и того же типа должны сравниваться как равные. Преобразование константы нулевого указателя в указатель на тип с квалификацией cv является однократным преобразованием, а не последовательностью преобразования указателя, за которым следует квалификационное преобразование ([conv.qual]). Константа нулевого указателя интегрального типа может быть преобразована в prvalue типа std :: nullptr_t. [Примечание: результирующее значение prvalue не является значением нулевого указателя. - конец примечания]
Что происходит «под капотом», которое позволяет компиляторам выполнять эти преобразования int-> void *?
Компилятор анализирует источник. Грамматика говорит, что 0 - литерал. Компилятор рассматривает это как литерал 0 и, как таковой, позволяет преобразовать его в любой тип указателя в соответствии со стандартом.
// Amazingly, even this seems to work with gcc, icc and msvc, but not with clang:
void * x = static_cast<int>(0);
Это плохо сформировано, начиная с C ++ 11. Когда неправильно сформированная программа компилируется, это обычно либо потому, что
- это расширение языка, либо
- это ошибка компилятора, либо
- правильно сформирована в более старой версии языка, и компилятор нацелен на это
В этом случае, вероятно, это расширение языка.
// These works for icc and msvc, but fails with gcc and clang
p = static_cast<int>(0);
g(static_cast<int>(0));
Они также плохо сформированы, так как C ++ 11 . Я недостаточно знаю о i cc и msv c, чтобы сказать вам, являются ли эти случаи преднамеренными. Я рекомендую проверить их документацию по этому поводу.