Подтвердить что ты не робот

Как проверить, является ли указатель NULL-указателем?

Я всегда думаю, что просто if(p != NULL){..} выполнит эту работу. Но после прочтения этого вопроса о переполнении стека, похоже, нет.

Итак, канонический способ проверки указателей NULL после поглощения всех обсуждений в этом вопросе, который говорит, что указатели NULL могут иметь ненулевое значение?

4b9b3361

Ответ 1

Я всегда думаю просто, если (p != NULL) {..} выполнит эту работу.

Это будет.

Ответ 2

Во-первых, чтобы быть на 100% ясным, нет никакой разницы между C и С++ Вот. И, во-вторых, вопрос о переполнении стека, который вы цитируете, не говорит о нулевых указателях; он вводит неверные указатели; которые, по крайней мере, до стандартом, вызывают поведение undefined, просто пытаясь Сравните их. В общем случае нет способа проверить, является ли указатель действительный.

В конце концов, существует три распространенных способа проверки нулевого указателя:

if ( p != NULL ) ...

if ( p != 0 ) ...

if ( p ) ...

Вся работа, независимо от представления нулевого указателя на машина. И все, так или иначе, вводят в заблуждение; какой ты выбор - это вопрос выбора наименее плохого. Формально первые два являются индентичными для компилятора; константа NULL или 0 преобразуется к нулевому указателю типа p, а результаты преобразования сравниваются с p. Независимо от представления нулевого указатель.

Третий немного отличается: p неявно преобразован до bool. Но неявное преобразование определяется как результат p != 0, поэтому вы получаете то же самое. (Это означает, что есть на самом деле нет действительного аргумента для использования третьего стиля — он запутывает с неявным преобразованием, без какой-либо компенсирующей выгоды.)

Какой из первых двух вы предпочитаете в основном вопрос стиля, возможно, частично продиктован вашим стилем программирования в другом месте: в зависимости от идиомы, одна из лжи будет более назойливой чем другой. Если бы это был только вопрос сравнения, я думаю, что большинство люди предпочитают NULL, но чем-то вроде f( NULL ), перегрузка, которая будет выбрана, будет f( int ), а не перегрузка с указатель. Аналогично, если f является шаблоном функции, f( NULL ) будет создать шаблон на int. (Конечно, некоторые компиляторы, например g++, генерирует предупреждение, если NULL используется в контексте не указателя; если вы используете g++, вам действительно нужно использовать NULL.)

В С++ 11, конечно, предпочтительная идиома:

if ( p != nullptr ) ...

что позволяет избежать большинства проблем с другими решениями. (Но это не является C-совместимым: -).)

Ответ 3

Компилятор должен предоставить систему согласованного типа и предоставить набор стандартных преобразований. Ни целочисленное значение 0, ни указатель NULL не должны быть представлены всеми нулевыми битами, но компилятор должен позаботиться о преобразовании токена "0" во входном файле в правильное представление для целочисленного нуля, а тип cast to pointer должен преобразовать из целочисленного в представление указателя.

Следствием этого является то, что

void *p;
memset(&p, 0, sizeof p);
if(p) { ... }

не гарантируется, что он будет вести себя одинаково во всех целевых системах, поскольку вы делаете предположение о битовой схеме здесь.

В качестве примера у меня встроенная платформа, которая не имеет защиты памяти и сохраняет векторы прерываний по адресу 0, поэтому по соглашению целые числа и указатели имеют XORed с 0x2000000 при преобразовании, который оставляет (void *) 0, указывая на адрес, который генерирует ошибку шины при разыменовании, однако тестирование указателя с помощью оператора if сначала возвращает его в целочисленное представление, а затем все нули.

Ответ 4

Фактическое представление нулевого указателя здесь не имеет значения. Integer литерал со значением 0 (включая 0 и любое допустимое определение NULL) можно преобразовать в любой тип указателя, указав нулевой указатель независимо от фактического представления. Таким образом, p != NULL, p != 0 и p - все допустимые тесты для непустого указателя.

У вас могут возникнуть проблемы с ненулевыми представлениями нулевого указателя, если вы написали что-то, скрученное как p != reinterpret_cast<void*>(0), поэтому не делайте этого.

Хотя я только что заметил, что ваш вопрос помечен как C, так и С++. Мой ответ относится к С++, а другие языки могут быть разными. На каком языке вы используете?

Ответ 5

По всей видимости, вы ссылаетесь на C++.

В C ваш фрагмент будет работать всегда. Мне нравится более простая if (p) { /* ... */ }.

Ответ 6

Представление указателей не имеет значения для их сравнения, поскольку все сравнения в C имеют место как значения не представления. Единственный способ сравнить представление - это нечто отвратительное, как:

static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...

Ответ 7

Ну, этот вопрос задавали и отвечали еще в 2011 году, но есть nullptr в С++ 11. Это все, что я использую в настоящее время.

Вы можете читать больше из Stack Overflow, а также из в этой статье.