В недавнем обзоре кода участник пытается обеспечить выполнение всех 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)
это просто абсолютная боль, чтобы найти и отладить.
Какой способ вы предпочитаете и почему?
c++
c
if-statement
null
coding-style
Брайан Мрамор
источник
источник
Ответы:
По моему опыту, тесты в форме
if (ptr)
илиif (!ptr)
являются предпочтительными. Они не зависят от определения символаNULL
. Они не раскрывают возможность случайного назначения. И они понятны и лаконичны.Редактировать: Как указывает SoapBox в комментарии, они совместимы с классами C ++, такими как
auto_ptr
объекты, которые действуют как указатели и которые обеспечивают преобразованиеbool
для включения именно этой идиомы. Для этих объектов явное сравнениеNULL
должно вызывать преобразование в указатель, которое может иметь другие семантические побочные эффекты или быть более дорогим, чем простая проверка существования, которуюbool
подразумевает преобразование.У меня есть предпочтение к коду, который говорит, что это означает, без лишнего текста.
if (ptr != NULL)
имеет то же значение, что иif (ptr)
за счет избыточной специфичности. Следующая логическая вещь - это писать,if ((ptr != NULL) == TRUE)
и в этом заключается безумие. Язык С ясно , что логическое значением проходит проверкуif
,while
или тому подобные имеет конкретный смысл ненулевого значения истинно и нуль является ложным. Избыточность не делает это понятнее.источник
int y = *x; if (!x) {...}
которой оптимизатору разрешено рассуждать о том, что, поскольку*x
он будет неопределенным, если онx
равен NULL, он не должен быть NULL и, следовательно,!x
должен быть FALSE. Выражение не!ptr
является неопределенным поведением. В этом примере, если тест был выполнен перед любым использованием , тогда оптимизатор ошибочно удалит тест.*x
if (foo)
достаточно ясно Используй это.источник
Я начну с этого: согласованность важна, решение менее важно, чем согласованность в вашей кодовой базе.
В C ++
NULL определяется как 0 или 0L в C ++.
Если вы читали язык программирования C ++, Бьярн Страуструп предлагает
0
явно использоватьNULL
макрос, чтобы избежать макроса при выполнении присваивания , я не уверен, что он делал то же самое со сравнениями, я давно читал книгу, думаю, он просто сделалif(some_ptr)
без явного сравнения, но я не уверен в этом.Причина этого в том, что
NULL
макрос обманчив (как почти все макросы), на самом деле он0
буквальный, а не уникальный тип, как следует из названия. Избегание макросов является одним из общих указаний в C ++. С другой стороны,0
выглядит как целое число, а не по сравнению с или присвоено указателям. Лично я мог бы пойти любым путем, но обычно я пропускаю явное сравнение (хотя некоторым людям это не нравится, поэтому, вероятно, у вас есть участник, предлагающий изменение в любом случае).Независимо от личных чувств, это во многом выбор наименьшего зла, поскольку не существует единственного правильного метода.
Это ясная и распространенная идиома, и я предпочитаю, что нет случайного присваивания значения во время сравнения, и он ясно показывает:
Это понятно, если вы знаете, что
some_ptr
это тип указателя, но это также может выглядеть как целочисленное сравнение:Это понятно, в общих случаях это имеет смысл ... Но это утечка абстракции,
NULL
на самом деле0
буквальная и может в итоге легко использоваться неправильно:C ++ 0x имеет nullptr, который теперь является предпочтительным методом, поскольку он явный и точный, просто будьте осторожны с случайным присваиванием:
До тех пор, пока вы не сможете перейти на C ++ 0x, я буду утверждать, что бесполезно беспокоиться о том, какие из этих методов вы используете, их все недостаточно, поэтому был изобретен nullptr (наряду с общими проблемами программирования, которые привели к идеальной пересылке). .) Самое главное, чтобы сохранить последовательность.
В С
С другой зверь.
В C NULL может быть определено как 0 или как ((void *) 0), C99 допускает реализацию определенных констант нулевого указателя. Так что на самом деле все сводится к определению реализации NULL, и вам придется проверить его в стандартной библиотеке.
Макросы очень распространены, и в целом они часто используются, чтобы восполнить недостатки в общей поддержке программирования на языке и других вещах. Язык намного проще и более распространена зависимость от препроцессора.
С этой точки зрения, вероятно, я бы рекомендовал использовать
NULL
определение макроса в C.источник
0
в C ++, это имеет смысл в C:(void *)0
.0
предпочтительнее, чемNULL
в C ++, потому что ошибки типа могут быть PITA.NULL
все равно равно нулю.#define NULL ((void *)0)
сlinux/stddef.h
NULL
должно быть ноль.Я пользуюсь
if (ptr)
, но об этом совершенно не стоит спорить.Мне нравится мой путь, потому что он лаконичен, хотя другие говорят,
== NULL
что его легче читать и более наглядно. Я вижу, откуда они берутся, я просто не согласен с тем, что дополнительные вещи делают это проще. (Я ненавижу макрос, поэтому я пристрастен.) До вас.Я не согласен с вашим аргументом. Если вы не получаете предупреждений о назначениях в условном выражении, вам нужно увеличить уровни предупреждений. Просто как тот. (И ради любви ко всему хорошему не переключайте их.)
Заметьте, в C ++ 0x мы можем сделать то
if (ptr == nullptr)
, что мне кажется лучше. (Опять же, я ненавижу макрос. Ноnullptr
это хорошо.) Но я все еще делаюif (ptr)
, только потому, что это то, к чему я привык.источник
Честно говоря, я не понимаю, почему это важно. Любой из них достаточно ясен, и любой, кто имеет умеренный опыт работы с C или C ++, должен понимать и то, и другое. Один комментарий, хотя:
Если вы планируете распознать ошибку и не продолжаете выполнять функцию (т.е. вы собираетесь сгенерировать исключение или немедленно вернуть код ошибки), вы должны сделать это защитным предложением:
Таким образом, вы избегаете «кода стрелки».
источник
if(!p)
является неопределенным поведением. Это может сработать или нет.if(!p)
это не неопределенное поведение, это строка перед ним. Иif(p==NULL)
будет иметь точно такую же проблему.Лично я всегда использовал
if (ptr == NULL)
это, потому что это ясно показывает мои намерения, но на данный момент это просто привычка.Использование
=
вместо==
будет поймано любым компетентным компилятором с правильными настройками предупреждений.Важным моментом является выбор единого стиля для вашей группы и его соблюдение. Независимо от того, каким путем вы пойдете, вы в конечном итоге привыкнете к нему, и потеря трения при работе с чужим кодом будет приветствоваться.
источник
Еще один момент в пользу
foo == NULL
практики: еслиfoo
, скажем, aint *
или abool *
, тоif (foo)
проверка может быть случайно интерпретирована читателем как проверка значения pointee, то есть asif (*foo)
.NULL
Сравнение здесь является напоминанием о том, что мы говорим о указателе.Но я полагаю, что хорошее соглашение об именах делает этот аргумент спорным.
источник
На самом деле, я использую оба варианта.
Есть ситуации, когда вы сначала проверяете правильность указателя, и если он равен NULL, вы просто возвращаете / выходите из функции. (Я знаю, что это может привести к обсуждению «должна ли функция иметь только одну точку выхода»)
Большую часть времени вы проверяете указатель, затем делаете то, что хотите, и затем устраняете ошибку. Результатом может быть уродливый код с отступом в x раз с несколькими if.
источник
goto
может быть очень удобным. Кроме того, во многих случаяхmalloc()
очистку можно заменить более быстройalloca()
. Я знаю, что они не рекомендуются, но они существуют по определенной причине (по моему мнению, хорошо названный ярлык дляgoto
намного чище, чем запутанноеif/else
дерево).alloca
является нестандартным и совершенно небезопасным. Если это не удается, ваша программа просто взрывается. Шансов на восстановление нет, а поскольку стек относительно небольшой, вероятен сбой. В случае неудачи возможно, что вы закроете кучу и введете уязвимости, компрометирующие привилегии. Никогда не используйтеalloca
или vlas, если у вас нет крошечной границы размера, который будет выделен (и тогда вы могли бы просто использовать обычный массив).Язык программирования C (K & R) попросит вас проверить на null == ptr, чтобы избежать случайного назначения.
источник
if (!valid)
вышеif (valid == 0
).Если стиль и формат будут частью ваших обзоров, должно быть согласованное руководство по стилю для сравнения. Если есть, делайте то, что говорит руководство по стилю. Если его нет, подробности, подобные этой, следует оставить, как они написаны. Это пустая трата времени и энергии и отвлекает от того, что обзоры кода действительно должны раскрывать. Серьезно, без руководства по стилю я бы настаивал на том, чтобы НЕ изменять такой код в принципе, даже если он не использует соглашение, которое я предпочитаю.
И не то, чтобы это имело значение, а мое личное предпочтение
if (ptr)
. Значение более очевидно для меня, чем дажеif (ptr == NULL)
.Может быть, он пытается сказать, что лучше разбираться с ошибочными условиями до счастливого пути? В этом случае я все еще не согласен с рецензентом. Я не знаю, что для этого существует общепринятая конвенция, но, на мой взгляд, наиболее «нормальное» условие должно стоять на первом месте в любом операторе if. Таким образом, мне нужно меньше копаться, чтобы выяснить, о чем эта функция и как она работает.
Исключением является то, что из-за ошибки я могу выйти из функции или я могу восстановить ее, прежде чем двигаться дальше. В этих случаях я сначала обрабатываю ошибку:
Имея дело с необычным состоянием, я могу позаботиться об этом, а потом забыть об этом. Но если я не могу вернуться к счастливому пути, обрабатывая его заранее, то он должен быть обработан после основного случая, потому что это делает код более понятным. По моему мнению.
Но если это не в руководстве по стилю, то это только мое мнение, и ваше мнение так же верно. Либо стандартизируйте, либо нет. Не позволяйте рецензенту псевдостандартизировать только потому, что у него есть мнение.
источник
Это одна из основ обоих языков, которую указатели оценивают по типу и значению, которые можно использовать в качестве контрольного выражения
bool
в C ++ иint
в C. Просто используйте его.источник
if (foo = bar)
случайно.Поэтому я предпочитаю
или
Однако, если бы я писал набор руководств по стилю, я бы не включал в него такие вещи, я бы писал такие:
источник
Я большой поклонник того , что C / C ++ не проверяет типы в логических условиях
if
,for
иwhile
заявлении. Я всегда использую следующее:даже на целые числа или другой тип, который преобразуется в bool:
Кодирование в этом стиле более читабельно и понятно для меня. Просто мое личное мнение.
Недавно, работая над микроконтроллером OKI 431, я заметил следующее:
более эффективен, чем
потому что в более позднем случае компилятор должен сравнить значение chx с 1. Где chx - просто флаг true / false.
источник
Большинство компиляторов, которые я использовал, будут по крайней мере предупреждать о
if
назначении без дополнительного синтаксического сахара, поэтому я не покупаю этот аргумент. Тем не менее, я использовал оба профессионально и не имею ни одного предпочтения. Это== NULL
определенно понятнее, хотя, на мой взгляд.источник