stringtranslate.com

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

В компьютерном программировании строка с нулевым завершением — это символьная строка, хранящаяся в виде массива , содержащего символы и заканчивающаяся нулевым символом (символ с внутренним значением, равным нулю, в этой статье называемый «NUL», а не то же самое, что нулевой глиф ). ). Альтернативные названия — C string , которая относится к языку программирования C, и ASCIIZ [1] (хотя C может использовать кодировки, отличные от ASCII ).

Длина строки определяется путем поиска (первого) NUL. Это может быть медленным, поскольку для этого требуется O( n ) ( линейное время ) относительно длины строки. Это также означает, что строка не может содержать NUL (в памяти есть NUL, но он находится после последнего символа, а не в строке).

История

Строки с нулевым завершением были созданы директивой .ASCIZассемблерных языков PDP-11 и директивой макроассемблерного языка MACRO-10 для PDP-10 . Они появились еще до разработки языка программирования C, но часто использовались и другие формы строк.ASCIZ

В то время, когда был разработан C (и языки, на которых он произошел), память была чрезвычайно ограничена, поэтому использование всего одного байта служебных данных для хранения длины строки было привлекательным. Единственная популярная в то время альтернатива, обычно называемая «строкой Паскаля» (более современный термин — « с префиксом длины »), использовала ведущий байт для хранения длины строки. Это позволяет строке содержать NUL, а для определения длины требуется только один доступ к памяти ( время O(1) (постоянное) ), но длина строки ограничена 255 символами. Дизайнер C Деннис Ритчи решил следовать соглашению о нулевом завершении, чтобы избежать ограничения на длину строки и потому, что, по его опыту, поддержание счетчика казалось менее удобным, чем использование терминатора. [2] [3]

Это оказало некоторое влияние на дизайн набора команд ЦП . Некоторые процессоры 1970-х и 1980-х годов, такие как Zilog Z80 и DEC VAX , имели специальные инструкции для обработки строк с префиксом длины. Однако по мере того, как строка с нулевым завершением получила распространение, разработчики процессоров начали принимать ее во внимание, как видно, например, из решения IBM добавить инструкции «Logical String Assist» в ES /9000 520 в 1992 году и инструкции для векторных строк в IBM z13 в 2015 году. [4]

Разработчик FreeBSD Пол-Хеннинг Камп , пишущий в ACM Queue , назвал победу строк с нулевым завершением над двухбайтовой (а не однобайтовой) длиной «самой дорогой однобайтовой ошибкой» за всю историю. [5]

Ограничения

Несмотря на простоту реализации, такое представление было подвержено ошибкам и проблемам с производительностью.

Нулевое завершение исторически создавало проблемы безопасности . [6] NUL, вставленный в середину строки, неожиданно обрезает ее. [7] Распространенной ошибкой было то, что дополнительное пространство для NUL не выделялось, поэтому оно записывалось в соседнюю память. Другой вариант заключался в том, чтобы вообще не записывать NUL, что часто не обнаруживалось во время тестирования, поскольку блок памяти уже содержал нули. Из-за затрат на поиск длины многие программы не утруждали себя копированием строки в буфер фиксированного размера , вызывая переполнение буфера , если она была слишком длинной.

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

Проблемы со скоростью определения длины обычно можно уменьшить, объединив ее с другой операцией, которая в любом случае имеет значение O( n ), например, в strlcpy. Однако это не всегда приводит к созданию интуитивно понятного API .

Кодировки символов

Строки с нулевым завершением требуют, чтобы в кодировке нигде не использовался нулевой байт (0x00); поэтому невозможно хранить все возможные строки ASCII или UTF-8 . [8] [9] [10] Однако подмножество ASCII или UTF-8 обычно хранится – каждый символ, кроме NUL – в строках с нулевым завершением. Некоторые системы используют « модифицированную UTF-8 », которая кодирует NUL как два ненулевых байта (0xC0, 0x80) и, таким образом, позволяет хранить все возможные строки. Это не допускается стандартом UTF-8, поскольку это слишком длинная кодировка , и это рассматривается как угроза безопасности. Вместо этого в качестве конца строки можно использовать какой-либо другой байт, например 0xFE или 0xFF, которые не используются в UTF-8.

В UTF-16 используются 2-байтовые целые числа, и поскольку любой байт может быть нулевым (и фактически любой другой байт при представлении текста ASCII), не может быть сохранен в строке байтов с нулевым завершением. Однако некоторые языки реализуют строку из 16-битных символов UTF-16 , заканчивающуюся 16-битным NUL (0x0000).

Улучшения

Было предпринято множество попыток сделать обработку строк C менее подверженной ошибкам. Одна из стратегий — добавить более безопасные функции, такие как strdupи strlcpy, и одновременно отказаться от использования небезопасных функций, таких как gets. Другой способ — добавить объектно-ориентированную оболочку вокруг строк C, чтобы можно было выполнять только безопасные вызовы. Однако в любом случае можно вызвать небезопасные функции.

Большинство современных библиотек заменяют строки C структурой, содержащей 32-битное или большее значение длины (намного больше, чем когда-либо считалось для строк с префиксом длины), и часто добавляют еще один указатель, счетчик ссылок и даже NUL для ускорения преобразования. вернемся к строке C. Память теперь намного больше, так что если добавление 3 (или 16 или более) байтов к каждой строке является реальной проблемой, программному обеспечению придется иметь дело с таким количеством маленьких строк, что какой-либо другой метод хранения сэкономит еще больше памяти. (например, дубликатов может быть так много, что хэш-таблица будет использовать меньше памяти). Примеры включают стандартную библиотеку шаблонов C++ , Qt , MFC и реализацию на основе C от Core Foundation , а также ее родственную версию Objective-C от Foundation , обе от Apple. Для хранения веревок, таких как веревка, также могут использоваться более сложные конструкции . std::string QString CStringCFStringNSString

Смотрите также

Рекомендации

  1. ^ «Глава 15 — Язык ассемблера MIPS» (PDF) . Карлтонский университет . Проверено 9 октября 2023 г.
  2. ^ Ричи, Деннис М. (апрель 1993 г.). Разработка языка Си. Вторая конференция по истории языков программирования. Кембридж, Массачусетс.
  3. ^ Ричи, Деннис М. (1996). «Развитие языка Си». В Бергине-младшем, Томасе Дж.; Гибсон-младший, Ричард Г. (ред.). История языков программирования (2-е изд.). Нью-Йорк: ACM Press. ISBN 0-201-89502-1– через Аддисон-Уэсли (Ридинг, Массачусетс).
  4. ^ Принципы работы IBM z/Architecture
  5. ^ Камп, Пол-Хеннинг (25 июля 2011 г.), «Самая дорогая однобайтовая ошибка», ACM Queue , 9 (7): 40–43, doi : 10.1145/2001562.2010365 , ISSN  1542-7730, S2CID  30282393
  6. Щенок тропического леса (9 сентября 1999 г.). «Проблемы Perl CGI». Журнал Фрак . artofhacking.com. 9 (55): 7 . Проверено 3 января 2016 г.
  7. ^ «Внедрение нулевых байтов в PHP?».
  8. ^ «UTF-8, формат преобразования ISO 10646» . Проверено 19 сентября 2013 г.
  9. ^ «Таблица символов Unicode/UTF-8» . Проверено 13 сентября 2013 г.
  10. ^ Кун, Маркус. «Часто задаваемые вопросы по UTF-8 и Unicode» . Проверено 13 сентября 2013 г.