Составно ли, если проверка на нуль, а затем другое условие в C всегда безопасна?

(этот вопрос является точной копией Составного, если проверка на нуль, а затем другие условия в C++ всегда безопасны? но о C, а не C++. Было отмечено, что вопрос должен быть более конкретным).

Я использовал следующий тип if состояние на много времени.

char* ptr = ...;
if (ptr != NULL && ptr[0] != '\0') // <=== is this always safe?
{ /* ... */ }

Опирается на ptr != NULL проверяться перед ptr[0] !='\0',

Это безопасно по всем стандартам, компиляторам, архитектурам? Или есть вероятность, что ptr[0] != '\0' будет проверено раньше ptr != NULL?

5 ответов

Да, это безопасно.

Стандарт C гласит (N1570 - 6.5.13 Логический оператор И):

В отличие от побитового двоичного оператора &, оператор && гарантирует оценку слева направо; если вычисляется второй операнд, между оценками первого и второго операндов существует точка последовательности. Если первый операнд сравнивается равным 0, второй операнд не оценивается.

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

Если ptr - это пользовательский тип (которого здесь нет), то это может не применяться, так как оператор && может быть переопределен в классе, и он НЕ ЗАКРЫВАЕТСЯ, как это.

На свой вопрос пишешь char* ptr = ...,

Таким образом, ответ зависит от контекста, в котором вы назначаете ptr со значением.

Пока вы назначаете ptr либо с действительным адресом памяти или с NULLтогда это должно быть безопасно.

Но если вы назначите ptr с неверным адресом памяти, который не NULLтогда ваш код небезопасен.

Например:

char* ptr = func();

char* func()
{
    char* str; // possibly pointing to an invalid memory address which is not NULL
    return str;
}

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

Если есть несколько потоков, выполняющих один и тот же код, и ptr не использует thread-local-storage, вполне может быть, что в

ptr != NULL && ptr[0] != '\0')

У вас есть последовательность как:

  • Поток 1 проверяет, что ptr != NULL правда.
  • Тема 2 назначает ptr = NULL
  • Поток 1 пытается получить доступ ptr[0] и сегфо.

Да, это безопасно. Это называется оценкой короткого замыкания и применяется к логическим и и логическим операторам.

В логическом и (&&) правая сторона оценивается, только если левая сторона истинна.

В логическом-или (||) правая сторона оценивается, только если левая сторона ложна.

Другие вопросы по тегам