Могу ли я использовать NULL
указатель в качестве замены для значения 0
?
Или что-то не так в этом?
Как, например:
int i = NULL;
как замена для:
int i = 0;
В качестве эксперимента я скомпилировал следующий код:
#include <stdio.h>
int main(void)
{
int i = NULL;
printf("%d",i);
return 0;
}
Вывод:
0
Действительно, это дает мне это предупреждение, которое само по себе совершенно правильно:
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
но результат все равно эквивалентен.
- Я перехожу в "Неопределенное поведение" с этим?
- Допустимо ли использовать
NULL
таким образом? - Что-то не так с использованием
NULL
в качестве числового значения в арифметических выражениях? - И каков результат и поведение в C ++ для этого случая?
Я прочитал ответы о том, в чем разница между NULL, '\ 0' и 0, о том, в чем разница NULL
, \0
и 0
есть, но я не получил оттуда краткую информацию, если она вполне допустима, а также правильно использовать NULL
как значение для работы в присваиваниях и других арифметических операциях.
Ответы:
Нет , это не безопасно.
NULL
является константой с нулевым указателем, которая может иметь типint
, но более типично имеет типvoid *
(в C) или иным образом не может быть напрямую назначенаint
(в C ++> = 11). Оба языка допускают преобразование указателей в целые числа, но они не предусматривают, чтобы такие преобразования выполнялись неявно (хотя некоторые компиляторы предоставляют это как расширение). Более того, хотя для преобразования нулевого указателя в целое число обычно используется значение 0, стандарт не гарантирует этого. Если вам нужна константа с типомint
и значением 0, тогда пишите по буквам0
.Да, в любой реализации, где
NULL
расширяется до значения с типомvoid *
или любого другого, не назначаемого напрямуюint
. Стандарт не определяет поведение вашего назначения в такой реализации, поэтому его поведение не определено.Это плохой стиль, и он сломается в некоторых системах и при некоторых обстоятельствах. Поскольку вы, похоже, используете GCC, в вашем собственном примере это не получится, если вы скомпилируете эту
-Werror
опцию.Да. Не гарантируется иметь числовое значение вообще. Если вы имеете в виду 0, то напишите 0, которое не только четко определено, но и короче и понятнее.
Язык C ++ более строг в отношении преобразований, чем C, и для него существуют другие правила
NULL
, но и здесь реализации могут предоставлять расширения. Опять же, если вы имеете в виду 0, то это то, что вы должны написать.источник
void *
», относится только к C.void *
не является допустимым типом для C ++ (потому что вы не можете назначитьvoid*
любой другой тип указателя). В C ++ 89 и C ++ 03 фактическиNULL
должен иметь типint
, но в более поздних версиях это может быть (и обычно так)nullptr_t
.void*
вint
неопределенное поведение. Не то; это поведение, заданное реализацией.NULL
некоторая константа нулевого указателя. В C это может быть целочисленное константное выражение со значением0
или такое выражение, приведенное кvoid*
, причем последнее более вероятно. Это означает, что вы не можете использоватьNULL
взаимозаменяемо с нулем. Например, в этом примере кодаЗамена
0
наNULL
гарантированно не будет допустимой программой на C, поскольку сложение между двумя указателями (не говоря уже о разных типах указателей) не определено. Это приведет к выдаче диагностики из-за нарушения ограничения. Операнды для сложения не будут действительными .Что касается C ++, все обстоит несколько иначе. Отсутствие неявного преобразования
void*
в другие типы объектов означало, чтоNULL
это исторически определено как0
в коде C ++. В C ++ 03 вам, вероятно, это сойдет с рук. Но начиная с C ++ 11 это может бытьnullptr
юридически определено как ключевое слово . Теперь снова выдает ошибку, так какstd::nullptr_t
не может быть добавлен к типу указателя.Если
NULL
определено какnullptr
то даже ваш эксперимент становится недействительным. Там нет преобразования изstd::nullptr_t
целого числа. Вот почему он считается более безопасной константой нулевого указателя.источник
NULL
в обоих языках.0
константы нулевого указателя: «очевидно, как подпорка для всего существующего плохо написанного кода C, который сделал неверные предположения»Правила варьируются между языками и их версиями. В некоторых случаях вы можете, а в других - нет. Независимо от того, вы не должны . Если вам повезет, ваш компилятор предупредит, если вы попытаетесь или, что еще лучше, не скомпилируете.
В C ++ до C ++ 11 (цитата из C ++ 03):
Не имеет смысла использовать константу нулевого указателя в качестве целого числа. Однако...
Таким образом, это будет технически работать, даже если это бессмысленно. Из-за этой технической возможности вы можете столкнуться с плохо написанными программами, которые злоупотребляют
NULL
.Начиная с C ++ 11 (цитата из последнего проекта):
A
std::nullptr_t
не может быть преобразовано в целое число, поэтому использование вNULL
качестве целого числа будет работать только условно, в зависимости от выбора, сделанного реализацией языка.PS
nullptr
это тип значенияstd::nullptr_t
. Если вам не нужна ваша программа для компиляции до C ++ 11, вы всегда должны использоватьnullptr
вместоNULL
.C немного отличается (цитаты из проекта C11 N1548):
Таким образом, случай аналогичен описанному в C ++ 11, т. Е. Злоупотребление
NULL
произведениями условно зависит от выбора, сделанного языковой реализацией.источник
Да , хотя в зависимости от реализации вам может понадобиться приведение. Но да, это на 100% законно, в противном случае.
Хотя это действительно, действительно, очень плохой стиль (само собой разумеется?).
NULL
есть, или был, на самом деле не C ++, это C. Стандарт же впрочем, как и для многих наследий C, имеет два положения ([diff.null] и [support.types.nullptr]) , которые технически сделатьNULL
C ++. Это определенная реализацией константа нулевого указателя . Поэтому, даже если это плохой стиль, технически он такой же C ++, каким может быть.Как указано в сноске , возможные реализации могут быть
0
или нет0L
, но не могут(void*)0
.NULL
может, конечно (стандарт прямо не говорит об этом, но это почти единственный выбор, оставшийся после0
или0L
)nullptr
. Это почти никогда не бывает, но это законная возможность.Предупреждение, которое показывал вам компилятор, демонстрирует, что компилятор на самом деле не соответствует (если вы не скомпилировали в режиме C). Потому что, согласно предупреждению, он преобразовал нулевой указатель (не тот,
nullptr
который был быnullptr_t
, который был бы отличен), так что, очевидно, определениеNULL
действительно(void*)0
, чего не может быть.В любом случае, у вас есть два возможных законных (то есть, не нарушенных компилятором) случая. Либо (реалистичный случай),
NULL
это что-то вроде0
или0L
, тогда у вас есть «ноль или один» преобразование в целое число, и вы готовы идти.Или
NULL
это действительно такnullptr
. В этом случае у вас есть отдельное значение, которое имеет гарантии относительно сравнения, а также четко определенные преобразования из целых чисел, но, к несчастью, не в целые числа. Тем не менее, он имеет четко определенное преобразование вbool
(в результатеfalse
) иbool
имеет четко определенное преобразование в целое число (в результате0
).К сожалению, это два преобразования, поэтому оно не находится в пределах «ноль или один», как указано в [conv]. Таким образом, если ваша реализация определяет
NULL
какnullptr
, то вам придется добавить явное приведение, чтобы ваш код был правильным.источник
Из C faq:
источник
Отказ от ответственности: я не знаю C ++. Мой ответ не предназначен для применения в контексте C ++
'\0'
этоint
со значением ноль, просто на 100% точно так же0
.В контексте указателей ,
0
иNULL
являются 100% эквивалентны:все 100% эквивалентны.
Примечание о
ptr + NULL
Контекст не
ptr + NULL
является указателем. Нет определения для добавления указателей в языке Си; указатели и целые числа могут быть добавлены (или вычтены). В случае либо или является указателем, а другой должен быть целым числом, так эффективно , или и в зависимости от определений и несколько поведений можно ожидать: все это работает, предупреждение для преобразования между указателем и целое, отказ компилировать, .. ,ptr + NULL
ptr
NULL
ptr + NULL
(int)ptr + NULL
ptr + (int)NULL
ptr
NULL
источник
#define NULL (void *)0
раньше. Вы уверены, что NULL и обычный 0 равны 100%?ptr + NULL
не используетсяNULL
в контексте указателейnullptr
есть, но((void*)0)
и0
(или'\0'
) эквивалентны в контексте указателей ...if (ptr == '\0' /* or equivalent 0, NULL */)
Нет, больше не используется
NULL
(старый способ инициализации указателя).Начиная с C ++ 11:
Ключевое слово
nullptr
обозначает литерал указателя. Это значение типа std :: nullptr_t. Существуют неявные преобразования изnullptr
нулевого значения указателя любого типа указателя и любого указателя на тип члена. Подобные преобразования существуют для любой константы нулевого указателя, которая включает значения типа,std::nullptr_t
а также макросNULL
.https://en.cppreference.com/w/cpp/language/nullptr
На самом деле, станд :: nullptr_t типа нулевого указателя буквального
nullptr
. Это отдельный тип, который сам по себе не является типом указателя или указателем на тип члена.Вывод:
источник