В чем смысл строк с нулевым завершением?

Как бы я ни любил C и C ++, я не могу не почесать голову при выборе строк с нулевым завершением:

  • Строки с префиксом длины (т.е. Pascal) существовали до C
  • Строки с префиксом длины ускоряют работу нескольких алгоритмов, разрешая поиск постоянной длины.
  • Строки с префиксом длины затрудняют возникновение ошибок переполнения буфера.
  • Даже на 32-битной машине, если вы разрешаете строке размер доступной памяти, строка с префиксом длины всего на три байта шире, чем строка с завершающим нулем. На 16-битных машинах это один байт. На 64-битных машинах разумным пределом длины строки является 4 ГБ, но даже если вы хотите расширить его до размера машинного слова, 64-битные машины обычно имеют достаточно памяти, что делает дополнительные семь байтов своего рода нулевым аргументом. Я знаю, что исходный стандарт C был написан для безумно плохих машин (с точки зрения памяти), но аргумент эффективности мне здесь не подходит.
  • Практически все остальные языки (например, Perl, Pascal, Python, Java, C #, и т. д.) используйте строки с префиксом длины. Эти языки обычно лучше C в тестах обработки строк, потому что они более эффективны со строками.
  • C ++ немного исправил это с помощью шаблона std :: basic_string , но простые символьные массивы, ожидающие строки с завершающим нулем, все еще широко распространены . Это также несовершенно, поскольку требует выделения кучи.
  • Строки с завершающим нулем должны зарезервировать символ (а именно, нулевой символ), который не может существовать в строке, в то время как строки с префиксом длины могут содержать встроенные нули.

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

РЕДАКТИРОВАТЬ : поскольку некоторые запрашивали фактов (и им не нравились те, которые я уже предоставил) о моей эффективности Как указано выше, они проистекают из нескольких вещей:

  • Concat с использованием строк с завершающим нулем требует сложности времени O (n + m). Префикс длины часто требует только O (m).
  • Длина с использованием строк с завершающим нулем требует сложности времени O (n). Префикс длины - O (1).
  • Длина и объединение являются наиболее распространенными строковыми операциями. Есть несколько случаев, когда строки с завершающим нулем могут быть более эффективными, но это происходит гораздо реже.

Из ответов ниже, это некоторые случаи, когда строки с завершающим нулем более эффективны:

  • Когда вам нужно отрезать начало строки и передать его какому-либо методу. Вы не можете сделать это за постоянное время с префиксом длины, даже если вам разрешено уничтожить исходную строку, потому что префикс длины, вероятно, должен соответствовать правилам выравнивания.
  • В некоторых случаях, когда вы просто просматриваете строку Посимвольно вы можете сохранить регистр ЦП. Обратите внимание, что это работает только в том случае, если вы не выделили строку динамически (потому что тогда вам придется освободить ее, что потребует использования сохраненного вами регистра ЦП для хранения указателя, который вы изначально получили от malloc и друзей).

Ничто из вышеперечисленного не так распространено, как length и concat.

В ответах ниже утверждается еще одно:

  • Вам нужно обрезать конец строки

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

272
задан PointerToConstantChar 21 March 2017 в 09:44
поделиться