Проверка указателя NULL в C / C ++

В недавнем обзоре кода вкладчик пытается обеспечить, чтобы все NULL проверки указателей выполнялись следующим образом:

 int * some_ptr; // ... if (some_ptr == NULL) { // Handle null-pointer error } else { // Proceed } 

вместо

 int * some_ptr; // ... if (some_ptr) { // Proceed } else { // Handle null-pointer error } 

Я согласен с тем, что его способ немного более ясен в том смысле, что он явно говорит «Удостоверьтесь, что этот указатель не является NULL», но я бы возразил, сказав, что любой, кто работает над этим кодом, поймет, что использование переменной указателя в if оператор неявно проверяет NULL . Также я чувствую, что второй метод имеет меньший шанс ввести ошибку ила:

 if (some_ptr = NULL) 

что является абсолютной болью для поиска и отладки.

В каком направлении вы предпочитаете и почему?

По моему опыту, тесты формы if (ptr) или if (!ptr) являются предпочтительными. Они не зависят от определения символа NULL . Они не предоставляют возможности для случайного назначения. И они ясны и кратки.

Изменить: Как отмечает SoapBox в комментарии, они совместимы с classами C ++, такими как auto_ptr которые являются объектами, которые действуют как указатели и которые обеспечивают преобразование в bool чтобы включить именно эту идиому. Для этих объектов явное сравнение с NULL должно было бы вызвать преобразование в указатель, который может иметь другие семантические побочные эффекты или быть более дорогостоящим, чем простая проверка существования, которую подразумевает преобразование bool .

Я предпочитаю код, который говорит, что это означает без ненужного текста. if (ptr != NULL) имеет то же значение, что и if (ptr) но за счет избыточной специфичности. Следующей логической задачей является запись if ((ptr != NULL) == TRUE) и таким образом происходит безумие. Язык C ясно, что логическое значение, проверенное if , while или т. Д., Имеет конкретное значение ненулевого значения, равно true, а ноль – false. Избыточность не уточняет.

if (foo) достаточно ясно. Используй это.

Я начну с этого: последовательность – это король, решение менее важно, чем последовательность в вашей базе кода.

В C ++

NULL определяется как 0 или 0L в C ++.

Если вы читали язык программирования на C ++, Bjarne Stroustrup предлагает использовать явно 0 чтобы избежать макроса NULL при выполнении задания , я не уверен, что он сделал то же самое со сравнением, прошло некоторое время с тех пор, как я прочитал книгу, я думаю, что он просто сделал if(some_ptr) без явного сравнения, но я if(some_ptr) в этом.

Причина этого заключается в том, что макрос NULL обманчив (как и почти все macros), он на самом деле является 0 литералом, а не уникальным типом, который, как предполагает название, может быть. Избегание макросов является одним из общих рекомендаций на C ++. С другой стороны, 0 выглядит как целое число, и оно не сравнивается или не привязывается к указателям. Лично я мог идти в любом случае, но обычно я пропускаю явное сравнение (хотя некоторым людям это не нравится, и, вероятно, почему у вас есть вкладчик, предлагающий изменения в любом случае).

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

Это понятно и распространенная идиома, и я предпочитаю ее, нет возможности случайно присвоить значение во время сравнения, и она ясно читает:

 if(some_ptr){;} 

Это понятно, если вы знаете, что some_ptr является типом указателя, но может также выглядеть как целочисленное сравнение:

 if(some_ptr != 0){;} 

Это понятно, в обычных случаях это имеет смысл … Но это нечеткая абстракция, NULL на самом деле является 0 литеральным и может быть легко использована неправильно:

 if(some_ptr != NULL){;} 

C ++ 0x имеет nullptr, который теперь является предпочтительным методом, поскольку он является явным и точным, просто будьте осторожны при случайном назначении:

 if(some_ptr != nullptr){;} 

Пока вы не сможете перейти на C ++ 0x, я бы сказал, что тратить время на беспокойство о том, какой из этих методов вы используете, все они недостаточны, поэтому был изобретен nullptr (наряду с типичными проблемами программирования, которые придумали идеальную пересылку .) Самое главное – поддерживать согласованность.

В C

C – другой зверь.

В C NULL может быть определено как 0 или как ((void *) 0), C99 допускает реализацию определенных констант нулевого указателя. Таким образом, это фактически сводится к определению NULL реализации, и вам придется его проверить в своей стандартной библиотеке.

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

С этой точки зрения я, вероятно, рекомендую использовать определение макроса NULL в C.

Я использую if (ptr) , но об этом не стоит спорить.

Мне нравится мой путь, потому что он краток, хотя другие говорят, что == NULL упрощает чтение и более явное. Я вижу, откуда они берутся, я просто не согласен с тем, что дополнительный материал облегчает его. (Я ненавижу макрос, поэтому я предвзятый.) До вас.

Я не согласен с вашими аргументами. Если вы не получаете предупреждения о назначении в условном выражении, вам нужно увеличить уровни предупреждений. Просто как тот. (И для любви ко всему, что хорошо, не переключайте их.)

Обратите внимание, что в C ++ 0x мы можем сделать if (ptr == nullptr) , что для меня лучше подходит . (Опять же, я ненавижу макрос, но nullptr хорош.) Я все еще делаю if (ptr) , хотя, только потому, что это то, к чему я привык.

Честно говоря, я не понимаю, почему это имеет значение. Любой из них достаточно ясен, и любой, кто имеет умеренный опыт работы с C или C ++, должен понимать и то, и другое. Один комментарий, хотя:

Если вы планируете распознать ошибку и не продолжать выполнение функции (т. Е. Вы собираетесь выбросить исключение или сразу же вернуть код ошибки), вы должны сделать это защитным предложением:

 int f(void* p) { if (!p) { return -1; } // p is not null return 0; } 

Таким образом, вы избегаете «кода стрелки».

На самом деле, я использую оба варианта.

Бывают ситуации, когда вы сначала проверяете правильность указателя, и если он NULL, вы просто возвращаете / выходите из функции. (Я знаю, что это может привести к обсуждению «если функция имеет только одну точку выхода»)

В большинстве случаев вы проверяете указатель, затем выполняете то, что хотите, а затем разрешаете ошибку. Результатом может быть уродливый x-times с отступом код с несколькими if.

Лично я всегда использовал if (ptr == NULL) потому что это делает мою цель явной, но на данный момент это просто привычка.

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

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

Еще один момент в пользу практики foo == NULL : если foo – это, скажем, int * или bool * , то проверка if (foo) может быть случайно интерпретирована читателем как проверяющая значение pointee, т.е. как if (*foo) . Сравнение NULL здесь напоминает нам о указателе.

Но я полагаю, что хорошее соглашение об именах делает этот спор спорным.

Язык программирования C (K & R) проведет проверку на null == ptr, чтобы избежать случайного назначения.

Если стиль и формат будут частью ваших обзоров, должно быть согласованное руководство по стилю для оценки. Если есть, сделайте то, что говорит стилист. Если их нет, детали, подобные этому, должны быть оставлены, поскольку они написаны. Это пустая трата времени и энергии и отвлекает от того, какие обзоры кода действительно должны быть раскрыты. Серьезно, без руководства по стилю я бы нажал, чтобы НЕ изменить код, подобный этому, в принципе, даже если он не использует соглашение, которое я предпочитаю.

И не это важно, но мое личное предпочтение – if (ptr) . Значение для меня становится более очевидным, чем даже if (ptr == NULL) .

Может быть, он пытается сказать, что лучше справляться с ошибками перед счастливым путем? В этом случае я до сих пор не согласен с рецензентом. Я не знаю, что для этого есть принятая конвенция, но, на мой взгляд, наиболее «нормальное» условие должно быть первым в любом утверждении if. Таким образом, мне нужно меньше копаться, чтобы выяснить, что это за функция и как она работает.

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

 if (error_condition) bail_or_fix(); return if not fixed; // If I'm still here, I'm on the happy path 

Когда я столкнулся с необычным состоянием, я могу позаботиться об этом, а потом забуду об этом. Но если я не смогу вернуться на счастливый путь, обработав его спереди, тогда его следует обработать после основного случая, потому что он делает код более понятным. По моему мнению.

Но если это не в руководстве по стилю, это просто мое мнение, и ваше мнение так же верно. Либо стандартизируйте, либо нет. Не позволяйте рецензента псевдо-стандартизировать только потому, что у него есть мнение.

Я думаю, это совершенно ясно:

 if( !some_ptr ) { // handle null-pointer error } else { // proceed } 

Прочитайте его как «Если нет указателя …»

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

Это одна из основ обоих языков, которые указатели оценивают по типу и значению, которые могут использоваться как контрольное выражение, bool в C ++ и int in C. Просто используйте его.

Я большой поклонник того факта, что C / C ++ не проверяет типы в логических условиях в операциях if , for и while . Я всегда использую следующее:

 if (ptr) if (!ptr) 

даже на целых или других типах, которые преобразуются в bool:

 while(i--) { // Something to do i times } while(cin >> a >> b) { // Do something while you've input } 

Кодирование в этом стиле более читаемо и яснее для меня. Просто мое личное мнение.

Недавно, работая над микроcontrollerом OKI 431, я заметил, что следующее:

 unsigned char chx; if (chx) // ... 

более эффективен, чем

 if (chx == 1) // ... 

потому что в более позднем случае компилятор должен сравнить значение chx с 1. Если chx является только флагом true / false.

Большинство компиляторов, которые я использовал, будут хотя бы предупреждать о назначении if без дальнейшего синтаксического сахара, поэтому я не покупаю этот аргумент. Тем не менее, я использовал как профессионально, так и не желаю. == NULL определенно яснее, хотя, на мой взгляд.

  • Указатели не являются булевыми
  • Современные компиляторы C / C ++ выдают предупреждение, когда вы пишите if (foo = bar) случайно.

Поэтому я предпочитаю

 if (foo == NULL) { // null case } else { // non null case } 

или

 if (foo != NULL) { // non null case } else { // null case } 

Однако, если бы я писал набор руководств по стилю, я бы не стал помещать в него такие вещи, я бы поставил такие вещи, как:

Убедитесь, что вы указали нулевой указатель.

  • Отключение автоматического форматирования в Visual Studio
  • Отладчик Visual Studio - отображение целочисленных значений в шестнадцатеричном виде
  • Что означает == $ 0 (double equals dollar zero) в инструментах разработчика Chrome?
  • Ошибка кодового знака: профиль Provisioning не найден.
  • Генерировать различные случайные числа в C #
  • Когда использовать утверждение и когда использовать исключение
  • Форматирование ReSharper: выравнивание равных операндов
  • «CompanyName.Foo» - это «пространство имен», но используется как «тип»,
  • Как получить «кодовое обозначение» gdb на OSX?
  • Подписывание ароматов продуктов с gradleиентом
  • Завершение кода PHP NetBeans
  • Давайте будем гением компьютера.