Ответ 1
Я всегда думаю просто, если (p != NULL) {..} выполнит эту работу.
Это будет.
Я всегда думаю, что просто if(p != NULL){..}
выполнит эту работу. Но после прочтения этого вопроса о переполнении стека, похоже, нет.
Итак, канонический способ проверки указателей NULL после поглощения всех обсуждений в этом вопросе, который говорит, что указатели NULL могут иметь ненулевое значение?
Я всегда думаю просто, если (p != NULL) {..} выполнит эту работу.
Это будет.
Во-первых, чтобы быть на 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-совместимым: -).)
Компилятор должен предоставить систему согласованного типа и предоставить набор стандартных преобразований. Ни целочисленное значение 0, ни указатель NULL не должны быть представлены всеми нулевыми битами, но компилятор должен позаботиться о преобразовании токена "0" во входном файле в правильное представление для целочисленного нуля, а тип cast to pointer должен преобразовать из целочисленного в представление указателя.
Следствием этого является то, что
void *p;
memset(&p, 0, sizeof p);
if(p) { ... }
не гарантируется, что он будет вести себя одинаково во всех целевых системах, поскольку вы делаете предположение о битовой схеме здесь.
В качестве примера у меня встроенная платформа, которая не имеет защиты памяти и сохраняет векторы прерываний по адресу 0, поэтому по соглашению целые числа и указатели имеют XORed с 0x2000000 при преобразовании, который оставляет (void *) 0, указывая на адрес, который генерирует ошибку шины при разыменовании, однако тестирование указателя с помощью оператора if
сначала возвращает его в целочисленное представление, а затем все нули.
Фактическое представление нулевого указателя здесь не имеет значения. Integer литерал со значением 0 (включая 0
и любое допустимое определение NULL
) можно преобразовать в любой тип указателя, указав нулевой указатель независимо от фактического представления. Таким образом, p != NULL
, p != 0
и p
- все допустимые тесты для непустого указателя.
У вас могут возникнуть проблемы с ненулевыми представлениями нулевого указателя, если вы написали что-то, скрученное как p != reinterpret_cast<void*>(0)
, поэтому не делайте этого.
Хотя я только что заметил, что ваш вопрос помечен как C, так и С++. Мой ответ относится к С++, а другие языки могут быть разными. На каком языке вы используете?
По всей видимости, вы ссылаетесь на C++
.
В C
ваш фрагмент будет работать всегда. Мне нравится более простая if (p) { /* ... */ }
.
Представление указателей не имеет значения для их сравнения, поскольку все сравнения в C имеют место как значения не представления. Единственный способ сравнить представление - это нечто отвратительное, как:
static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
Ну, этот вопрос задавали и отвечали еще в 2011 году, но есть nullptr
в С++ 11. Это все, что я использую в настоящее время.
Вы можете читать больше из Stack Overflow, а также из в этой статье.