Лучше использовать OR или AND при проверке на NULL в операторах C if? - PullRequest
2 голосов
/ 17 июня 2010

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

if (!*pos)
  return NULL;
if (!*pos || ((*pos)->flags == FLAGS))
  return blah;

Есть ли разница (производительность / безопасность / параллелизм) в этом вместо:

if (!*pos) 
  return NULL;
if (*pos && ((*pos)->flags == FLAGS))
  return blah;

Спасибо, Chenz

Ответы [ 4 ]

6 голосов
/ 17 июня 2010

Почему бы и нет:

if (!*pos) 
  return NULL;
if ((*pos)->flags == FLAGS)
  return blah;

Исходный код (комментарии удалены):

if (!pos)
    return NULL;
if (!*pos)
    return BIO_new(BIO_s_null());
if (!*pos || ((*pos)->flags == ASN1_STRING_FLAG_CONT))
    return BIO_new(BIO_s_mem());
return BIO_new_mem_buf((*pos)->data, (*pos)->length);

Если тесты проводились по какой-то сомнительной причине безопасности, разве не должен быть третий тест?:

if ( pos && *pos && ((*pos)->flags == ASN1_STRING_FLAG_CONT))

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

2 голосов
/ 17 июня 2010

Похоже, что первая строка отменяет первое условие второго, но все же хорошей практикой является оставлять проверки на ненулевое значение перед разыменованием, если более ранний код когда-либо удаляется, или если код, который изменяет pos (устанавливает его вNULL) всегда размещается между этими разделами.(один существенный недостаток return в середине функции здесь ...)

Кроме этого, не должно быть никакой разницы с любым оптимизирующим компилятором, но код может лучше передать идею: return blah либо, если * pos - NULL, либо если флаги - FLAGS;несмотря на более раннее условие, которое выделяет pos == NULL, в этом месте логика выполнения может также позволить ему быть NULL и выполнять возврат, как описано, вместо пропуска этого места.*

Это все равно будет работать правильно, управление возвращается, если pos == NULL, только другой возврат.

Любое изменение в более позднем условии изменит поведение:

 if (*pos && ((*pos)->flags == FLAGS))
   return blah;
 crash();
2 голосов
/ 17 июня 2010

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

if (!*pos || ((*pos)->flags == FLAGS))
   // reached if *pos is NULL or the flags are set
   return blah;

if (*pos && ((*pos)->flags == FLAGS))
   // reached if *pos is not NULL and the flags are set 
   return blah;

||форма заставит функцию вернуть бла, если она была достигнута с * pos, равным NULL.

(поскольку код следует за оператором, который заставляет функцию возвращать NULL, если * pos равен NULL, тест, вероятно, является избыточным, предполагая, что posуказывает на нормальную память, а не на летучую)

1 голос
/ 17 июня 2010

Видя такой код, эффективность - не тот вопрос, который нужно задавать.Мне не нравится ни одна из версий.Я бы пошел на

if (!*pos)
  return NULL;
else if((*pos)->flags == FLAGS)
  return blah;

Чисто, однозначно, эффективно.

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