Почему strlen () не считает байт завершающего NUL-символа, если NUL-символ определен как часть строки? - PullRequest
0 голосов
/ 19 октября 2019

Я знаю, что strlen() не считает NUL-оканчивающийся символ с. Я действительно знаю, что это факт. Таким образом, этот вопрос НЕ касается вопроса о том, почему strlen() может «предположительно» не возвращать правильную длину строки, на которую уже много раз задавали и отвечали здесь, в StackOverflow, например, в этом потоке или этот .

Итак, давайте перейдем к моему вопросу:

В ИСО / МЭК 9899: 1990 (E);7.1.1., Указано:

Строка - это непрерывная последовательность символов, оканчивающаяся на и включающая первый нулевой символ.

Чтоявляется причиной, по которой strlen() отклоняется от этого сформированного стандарта и не "хочет" принять строку с ее NUL-оканчивающимся символом?

Почему?

Ответы [ 4 ]

5 голосов
/ 19 октября 2019

Поскольку вы ожидаете, что утверждение этого псевдокода будет иметь значение true:

str1 = "foo"
str2 = "bar"
str3 = concatenate(str1, str2)

Assert strlen(str1) + strlen(s2) == strlen(str3)

Если завершение '\0' было засчитано strlen, вышеприведенное утверждение не будет выполнено, что будет гораздо большей общей головной болью,чем текущее поведение строки C. Что еще более важно, это было бы, на мой взгляд, довольно неинтуитивно и нелогично.

3 голосов
/ 19 октября 2019

Не совсем ответ на ваш вопрос, но рассмотрим следующий пример:

char string[] = "string";
printf("sizeof: %zu\n", sizeof(string));
printf("strlen: %zu\n", strlen(string));

Это печатает

sizeof: 7
strlen: 6

Так что sizeof считает \0, но strlenне.

Подобные вопросы, которые задают вопрос, почему определенное вековое решение было принято так или иначе, трудно ответить. Я могу сказать, что для me в любом случае совершенно очевидно, что strlen должен считать только реальные, "интересные" символы, которые в строке, и игнорировать \0в конце, который просто завершает его. Я привык к учету \0 отдельно. Я полагаю, что было бы значительно больше неприятностей, если бы strlen был определен иначе. Но я не могу доказать это убедительными аргументами, и я использовал strlen с его текущим определением так долго, что я, вероятно, безнадежно предвзят;Я мог бы сказать «для меня совершенно очевидно, что ...», даже если определение strlen было совершенно неверным.

2 голосов
/ 19 октября 2019

Существует различие между физическим, сохраненным представлением строки стиля C и логическим представлением строки стиля C.

Физическое представление того, как строка фактически хранится в памяти или других носителях, включаетнулевой символ. Нулевой символ включается при обсуждении физического представления, поскольку он занимает дополнительную часть памяти. Для того чтобы быть строкой в ​​стиле C, нулевой символ должен быть сохранен.

Однако логическое представление строки не включает нулевой символ. Логическое представление строки включает в себя только текстовые символы, которыми программист хочет манипулировать.

Я подозреваю, что нулевой символ, значение двоичного нуля, был выбран из-за того, что исходный набор символов ASCII определил символзначение ноль в качестве символа NULL. Часть более низких значений среди различных управляющих кодов телетайпа, кажется, наименее вероятный символ ASCII, который может появиться в тексте. См. Коды символов ASCII .

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

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

Различные функции манипуляции со строками в стиле Cв стандартной библиотеке (strlen(), strcpy() и т. д.) все разработано вокруг логического представления строки стиля C. Они выполняют свои действия, используя нулевой символ как не являющийся частью текста, а скорее как специальный индикаторный символ, который указывает конец строки. Однако, как часть их операций, они должны знать о нулевом символе и его использовании в качестве специального символа. Например, когда strcpy() или strcat() используются для копирования строк, они также должны копировать нулевой символ, указывающий конец строки, даже если он не является частью фактического текста логического представления.

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

C ++ может предоставить std::string благодаря своей объектно-ориентированной поддержке и наличию дополнительных возможностей языка, позволяющих создавать и управлять объектами. В языке программирования C из-за его простого синтаксиса и отсутствия объектно-ориентированных возможностей это удобство отсутствует.

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

2 голосов
/ 19 октября 2019

Принимая ваши сомнения за разумный аргумент, мы можем утверждать, что: C-строка состоит из двух частей:

  1. полезное содержимое строки («текст»);
  2. завершающий нулевой символ;

Завершающий нулевой символ является чисто технической мерой для определения конца строки библиотечными функциями, созданными на языке Си. Тем не менее, если кто-то напечатает объявление:

char * str = "some string";

, они логически ожидают, что его длина будет 11, что столько, сколько они могут видеть в этом утверждении. Следовательно, значение strlen() дает только длину части 1. строки.

...