Как мы можем проверить, является ли указатель нулевым указателем? - PullRequest
41 голосов
/ 31 мая 2011

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

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

Ответы [ 7 ]

49 голосов
/ 31 мая 2011

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

Это будет.

29 голосов
/ 31 мая 2011

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

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

if ( p != NULL ) ...

if ( p != 0 ) ...

if ( p ) ...

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

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

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

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

if ( p != nullptr ) ...

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

9 голосов
/ 31 мая 2011

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

Смысл этого в том, что

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

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

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

6 голосов
/ 31 мая 2011

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

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

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

4 голосов
/ 31 мая 2011

Очевидно, что вы ссылаетесь на нить примерно C++.

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

2 голосов
/ 31 мая 2011

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

static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
1 голос
/ 20 февраля 2015

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

Вы можете прочитать больше из Переполнения стека , а также из этой статьи .

...