Читаю Мейерса, возник базовый вопрос, который наверное и задать стыдно. Но тем не менее. Не совсем понимаю, что за типы у 0 и NULL. Почему в коде ниже не компилируются закомментированные строки?
Выходит, просто 0 или NULL компилятор может сконверитировать в указатель; (int)0 и (int)NULL тоже может. Но если 0 или NULL передаются как параметр функции типа int, то компилятор уже не может превратить их в указатель? В чём разница?
Здравствуйте, RiNSpy, Вы писали:
RNS>Выходит, просто 0 или NULL компилятор может сконверитировать в указатель; (int)0 и (int)NULL тоже может.
эти два выражения не должны конвертироваться в указатель. у них тип int
RNS>Но если 0 или NULL передаются как параметр функции типа int, то компилятор уже не может превратить их в указатель? В чём разница?
литеральный 0 может преобразовываться в указатель. за это отвечает не система типов, а компилятор. то есть он видит литеральный ноль + видит передачу указателя -> он передает нулевой указатель
в других ситуациях 0 является константой с типом int
варианты из вашего примера, которые также не должны компилироваться:
нюанс с литеральным нулем очень важен. в компиляторах есть баги, когда они даже constexpr выражение 1-1 способны преобразовывать к нулевому указателю, однако не должны
NULL — это некоторая константа, которая умеет преобразовываться к нулевому указателю. ее тип — implementation defined. бывает int (литеральный 0), а бывает void*
собственно, чтобы немного уменьшить кол-во зоопарка и ввели nullptr, у которого есть даже свой тип — nullptr_t
Здравствуйте, uzhas, Вы писали:
U>литеральный 0 может преобразовываться в указатель. за это отвечает не система типов, а компилятор. то есть он видит литеральный ноль + видит передачу указателя -> он передает нулевой указатель U>в других ситуациях 0 является константой с типом int
Т.е. это специальный хак такой, именно для литерального 0?
uzhas:
U>нюанс с литеральным нулем очень важен. в компиляторах есть баги, когда они даже constexpr выражение 1-1 способны преобразовывать к нулевому указателю, однако не должны
Это не баг, а вполне себе правильное для C++98 — C++11 поведение. Разработчики просто не успели или не захотели реализовать breaking change из C++14 (которое потенциально может привести к появлению реальных багов в старых программах).
U>NULL — это некоторая константа, которая умеет преобразовываться к нулевому указателю. ее тип — implementation defined. бывает int (литеральный 0), а бывает void*
Здравствуйте, N. I., Вы писали:
NI>Это не баг, а вполне себе правильное для C++98 — C++11 поведение.
для С++14 это вроде баг
решил на уровне стандарта найти разницу, вроде нашел:
С++11
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to
zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the
result is the null pointer value of that type and is distinguishable from every other value of pointer to object
or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion
of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a
pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can
be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value.
—end note ]
С++14
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type
and is distinguishable from every other value of object pointer or function pointer type. Such a conversion
is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The
conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the
sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of
integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a
null pointer value. —end note ]
NI>void* может быть в C, но не в C++.
хотел подчеркнуть, что стандартом не регламентируется какого типа NULL. вроде зафиксировано, что это макрос, но в доках не нашел =\
uzhas:
NI>>Это не баг, а вполне себе правильное для C++98 — C++11 поведение.
U>для С++14 это вроде баг
Багами в программе (в данном случае — компиляторе) обычно называют ошибки, из-за которых она работает не так, как было задумано разработчиком. Если багом называть любое nonconformance с неким новым стандартом, то любой старый компилятор, который разрабатывался для поддержки C++03 или C++11, внезапно станет ну просто-таки суперзабагованным.
NI>>void* может быть в C, но не в C++. U>хотел подчеркнуть, что стандартом не регламентируется какого типа NULL. вроде зафиксировано, что это макрос, но в доках не нашел =\
Здравствуйте, uzhas, Вы писали:
U>хотел подчеркнуть, что стандартом не регламентируется какого типа NULL. вроде зафиксировано, что это макрос, но в доках не нашел =\
Можно и не в доках...
GCC
stddef.h
/* A null pointer constant. */#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */#ifdef __GNUG__
#define NULL __null
#else/* G++ */#ifndef __cplusplus
#define NULL ((void *)0)
#else/* C++ */#define NULL 0
#endif/* C++ */#endif/* G++ */#endif/* NULL not defined and <stddef.h> or need NULL. */#undef __need_NULL