Составно ли, если проверка на нуль, а затем другое условие в 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]
и сегфо.
Да, это безопасно. Это называется оценкой короткого замыкания и применяется к логическим и и логическим операторам.
В логическом и (&&) правая сторона оценивается, только если левая сторона истинна.
В логическом-или (||) правая сторона оценивается, только если левая сторона ложна.