Является ли составным, если проверка на null, а затем другое условие в C всегда безопасно?

(этот вопрос является точной копией Is-соединения, если вы проверяете значение null, а затем другое условие в 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 ?

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

C говорит (N1570 – 6.5.13 Логический оператор И):

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

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

Если ptr является определяемым пользователем типом (который здесь не указан), это может не применяться, так как оператор && может быть переопределен в classе и не является короткозамкнутым.

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

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

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

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

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

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

У вас есть последовательность, например:

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

В вашем вопросе вы пишете 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; }