Почему инициализация значения «int * ptr = int ()» не является незаконной?


86

Следующий код (взят отсюда ):

int* ptr = int();

компилируется в Visual C ++ и инициализирует указатель значением.

Как такое возможно? Я имею в виду, что int()дает объект типа, intи я не могу присвоить intуказателю.

Как приведенный выше код не является незаконным?


Не ответ, а отличный вопрос! Я такого не видел.
— Джош

6
Так как примитивы имеют «конструктор» в C ++, int()дает значение построено значение int(которое я думаю, что C ++ 03 указано , что) и значение по умолчанию intявляется 0. Это эквивалентноint *ptr = 0;
— wkl

7
@EmanuelEy: Нет, любая целочисленная константа с нулевым значением может использоваться как константа нулевого указателя, независимо от того, как указатели фактически реализованы.
— Майк Сеймур,

1
@MooingDuck: Я не сказал, что это NULLможет быть ненулевое значение. Я сказал, что это может быть любая целочисленная константа с нулевым значением (включая int()).
— Майк Сеймур,

5
@DanielPryden Это использование слова «объект», о котором я раньше не подозревал.
— пушистый

Ответы:


110

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


3
+1, бит константного выражения важен и отсутствует в 2 лучших ответах.
— Дэвид Родригес - dribeas

это уходит с C ++ 0x?
— Neil G

@NeilG: это остается неизменным в C ++ 11, хотя теперь есть также nullptr, который вы можете использовать вместо 0или NULLв новом коде.
— Джерри Коффин,

2
@Nils: Ясность кода и заявление о намерениях посредством кода. Конечно, с C ++ 11 теперь вы хотите использовать nullptr, потому что он также добавляет преимущества дополнительных проверок во время компиляции.
— Джамин Грей

3
@Nils, потому что совершенно очевидно, что это 0может означать константу нулевого указателя или число 0, в то время nullptrкак очевидна константа нулевого указателя. Вдобавок, как сказал Джамин, он также имеет «дополнительные проверки во время компиляции». Постарайтесь подумать, прежде чем печатать.
— Miles Rout

35

Потому что int()урожаи 0, которые взаимозаменяемы с NULL. NULLсам определяется как 0, в отличие от C, NULLкоторый есть (void *) 0.

Обратите внимание, что это будет ошибкой:

int* ptr = int(5);

и это все равно будет работать:

int* ptr = int(0);

0- это особое постоянное значение, которое может рассматриваться как значение указателя. Константные выражения, которые дают результат 0, такие 1 - 1как допустимые как константы с нулевым указателем.


1
Также обратите внимание, что NULL C также не обязательно (void *)0. Это просто реализация, определяемая «целочисленным постоянным выражением со значением 0 или таким выражением, приведенным к типу void *».
— Джерри Коффин

@JerryCoffin Я никогда не использовал компилятор C, который определялся NULLкак (void*)0; так было всегда 0(а может быть 0L). (Но потом, к тому времени, когда C90 легализовали (void*)0в C, я уже использовал C ++.)
— Джеймс Канце,

1
@JamesKanze: В ubuntu 11.04 и в нашей собственной #if !defined(__cplusplus) \n #define NULL ((void*)0) \n #else \n #define NULL (0)версии Linux libio.h содержит: текущая версия gcc в ubuntu - 4.5, в нашей системе - 4.0.
— Дэвид Родригес - dribeas

5
" 0является особым литералом" - только потому, что это постоянное выражение, и оно имеет специальное значение 0. Не (1-1)менее особенное, это также константа нулевого указателя, и так далее int(). Факт 0быть буквальным является достаточным, но не обязательным условием, чтобы быть постоянным выражением. Что-то вроде этого strlen(""), хотя оно также имеет особое значение 0, не является постоянным выражением и, следовательно, не является константой нулевого указателя.
— Стив Джессоп,

@SteveJessop: Я согласен с поправкой, это действительно постоянное значение 0, а не 0буквальное значение.
— Благовест Буюклиев

18

Выражение int()вычисляется как постоянное инициализированное по умолчанию целое число, которое является значением 0. Это значение является особенным: оно используется для инициализации указателя на состояние NULL.


2
Здесь отсутствует очень важная деталь, присутствующая в ответе Джерри: недостаточно того, что выражение дает значение 0, но оно также должно быть константным выражением . Для контрпримера с int f() { return 0; }, выражение f()дает значение 0, но его нельзя использовать для инициализации указателя.
— Дэвид Родригес - dribeas

@ DavidRodríguez-dribeas, в спешке дать ответ в самых простых терминах я упустил эту часть. Надеюсь, сейчас это приемлемо.
— Марк Рэнсом

13

Из n3290 (C ++ 03 использует аналогичный текст), 4.10 Преобразования указателей [conv.ptr], абзац 1 (выделено мной):

1 Константа нулевого указателя - это целочисленное постоянное выражение (5.19) prvalue целочисленного типа, которое оценивается как ноль, или prvalue типа std :: nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является значение нулевого указателя этого типа, которое можно отличить от любого другого значения указателя на объект или типа указателя на функцию. Такое преобразование называется преобразованием нулевого указателя. [...]

int()- такое интегральное постоянное выражение prvalue целочисленного типа, которое оценивается как ноль (это полный рот!), и поэтому может использоваться для инициализации типа указателя. Как видите, 0это не единственное интегральное выражение, имеющее специальный регистр.


4

Ну, int - это не объект.

Я полагаю, что здесь происходит то, что вы говорите int * указать на некоторый адрес памяти, определенный int ()

поэтому, если int () создает 0, int * будет указывать на адрес памяти 0


1
int()безусловно , это объект.
— Гонки за легкостью на орбите,

@Tomalak: Я не думаю, что это так. Это временное явление неклассового типа, и я думаю, я прав, говоря, что это не объекты в том, что касается стандарта C ++. Хотя это немного странно, раздел «временные объекты» начинается с осторожного разговора только о временных объектах типа класса, но позже в нем говорится о привязке ссылок, и, конечно, вы можете привязать ссылку к int(). Определите int i;, тогда не вопрос, iэто объект.
— Стив Джессоп,

@Steve: Я бы ожидал споров по этому поводу, потому что «объекты» - это область хранения в C ++, а временные библиотеки на самом деле не имеют хранилища, верно? 1.8 / 1 явно не перечисляет временные, но кажется, что есть намерение включить их.
— Гонки легкости на орбите

1
@Tomalak: да, действительно, временные файлы неклассового типа не нуждаются в хранилище, если вы не берете ссылку. Неважно, это не имеет большого значения. Утверждение «ну, int не является объектом» истинно только потому, что intэто тип, а не объект. Будь int()дает объект или просто Rvalue не влияет на что - нибудь кто - нибудь говорил в другом месте.
— Стив Джессоп,

@Steve: Это многое undebateable :)
— светлота Гонка в Orbit
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.