strlen не проверяет наличие NULL

#c #segmentation-fault #strlen

#c #ошибка сегментации #стрлен #strlen

Вопрос:

Почему strlen() не проверяется наличие NULL?

если я это сделаю strlen(NULL) , произойдет ошибка сегментации программы.

Пытаюсь понять стоящее за этим обоснование (если таковое имеется).

Комментарии:

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

Ответ №1:

Логика, стоящая за этим, проста — как вы можете проверить длину чего-то, чего не существует?

Также, в отличие от «управляемых языков», нет ожиданий, что система времени выполнения будет корректно обрабатывать недопустимые данные или структуры данных. (Именно из-за этого типа проблем более «современные» языки более популярны для приложений, не требующих вычислений или менее производительных).

Стандартный шаблон на c выглядел бы следующим образом

  int someStrLen;

 if (someStr != NULL)  // or if (someStr)
    someStrLen = strlen(someStr);
 else
 {
    // handle error.
 }
  

Комментарии:

1. «Управляемый»… Это верно. Представьте, что каждая функция начинается очень параноидально и проверяет каждую возможную ошибку. Printf хранит метаинформацию для каждого аргумента в списке, каждая математическая операция проверяет переполнение и т.д. Это управляемо.

2. Я принимаю исключение из «стандартного шаблона». Если someStr предполагается, что указатель указывает на строку, он никогда не должен быть указателем null при достижении этой точки в программе. Некоторые люди используют указатели null в качестве специального «пустого» значения, но это не универсальное соглашение, и я бы сказал, что это приносит намного больше вреда, чем пользы…

3. @R Я предполагаю, что мы не согласны с тем, что означает «стандартный шаблон». Может быть, вы предпочли бы «полезный шаблон»? Если вам больше нравится этот термин, я не против.

4. В c11 есть strnlen_s(str, strsz) который возвращает ноль, если str является нулевым указателем.

5. @jfs он делает больше, чем это, он также ограничивает возвращаемый максимальный размер. Но вы правильно подметили, что это явно лучший выбор для надежной программы.

Ответ №2:

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

Философия, лежащая в основе разработки стандартной библиотеки C, заключается в том, что программист в конечном счете находится в наилучшем положении, чтобы знать, действительно ли необходимо выполнять проверку во время выполнения. В те времена, когда общая системная память измерялась в килобайтах, накладные расходы на выполнение ненужной проверки во время выполнения могли быть довольно болезненными. Таким образом, стандартная библиотека C не утруждает себя выполнением какой-либо из этих проверок; предполагается, что программист уже сделал это, если это действительно необходимо. Если вы знаете, что никогда не передадите неверное значение указателя на strlen (например, вы передаете строковый литерал или локально выделенный массив), то нет необходимости загромождать результирующий двоичный файл ненужной проверкой на NULL.

Комментарии:

1. 1 для «Если вы знаете, что вы никогда не передадите неверное значение указателя».

2. «Часть» — это C17 7.1.4.1.

Ответ №3:

Стандарт этого не требует, поэтому реализации просто избегают тестирования и потенциально дорогостоящего перехода.

Ответ №4:

Небольшой макрос, чтобы помочь вашему горю:

 #define strlens(s) (s==NULL?0:strlen(s))
  

Комментарии:

1. Просто не вызывайте его как strlens(p )

2. В первую очередь избегайте макросов.

Ответ №5:

Три существенные причины:

  • Стандартная библиотека и язык C разработаны с учетом того, что программист знает, что он делает, поэтому нулевой указатель рассматривается не как крайний случай, а скорее как ошибка программиста, которая приводит к неопределенному поведению;

  • Это приводит к накладным расходам во время выполнения — вызывать strlen тысячи раз и всегда выполнять str != NULL нецелесообразно, если к программисту не относятся как к неженке;

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

Комментарии:

1. Некоторые стандартные функции C проверяют NULL входные данные, поэтому первая причина является фиктивной. Третья причина также фиктивна, потому что добавление нескольких дополнительных проверок в библиотеку увеличивает размер кода меньше (на типичной, не встроенной платформе), чем все проверки, вставленные в клиентский код.

2. @larsmans: причина номер один была не окончательным утверждением, а скорее попыткой описать преобладающее мышление в программировании на C; причина номер три имеет смысл, когда вы уверены, что указатель не может быть NULL в клиентском коде, и такая проверка действует скорее как assert утверждение.

3. @larsmans: о, но большинство функций, которые проверяют NULL , находятся в «более новых» частях стандарта (например: mb* , wc* ), не так ли?

4. @ninjalj: И проверка на NULL на самом деле является самым большим недостатком в интерфейсах wc / mb. Общая потребность в этих функциях заключается в обработке одного байта / символа за раз, и выполнение нескольких бесполезных проверок нулевого указателя при каждом вызове может легко удвоить время, затрачиваемое на них.

5. @R ..: конечно, я просто указывал, что существование этих функций на самом деле не является контрпримером первого пункта Blagovest.

Ответ №6:

 size_t strlen ( const char * str );
  

http://www.cplusplus.com/reference/clibrary/cstring/strlen/

Strlen принимает указатель на массив символов в качестве параметра, null не является допустимым аргументом для этой функции.