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 назвал победу строк с завершающим нулем над строками длиной в 2 байта (а не в один байт) «самой дорогой ошибкой в ​​один байт» из когда-либо существовавших. [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++ Standard Template Library std::string , Qt QString , MFC CString и реализация на основе C CFStringот Core Foundation , а также ее родственный Objective-CNSString от Foundation , обе от Apple. Более сложные структуры также могут использоваться для хранения строк, таких как rope .

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

Ссылки

  1. ^ "Глава 15 - Язык ассемблера MIPS" (PDF) . Карлтонский университет . Получено 9 октября 2023 г. .
  2. ^ Ритчи, Деннис М. (апрель 1993 г.). Развитие языка C. Вторая конференция по истории языков программирования. Кембридж, Массачусетс.
  3. ^ Ритчи, Деннис М. (1996). «Развитие языка C». В Bergin, Jr., Thomas J.; Gibson, Jr., Richard G. (ред.). История языков программирования (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. Rain Forest Puppy (9 сентября 1999 г.). «Проблемы Perl CGI». Phrack Magazine . 9 (55). artofhacking.com: 7. Получено 3 января 2016 г.
  7. ^ «Внедрение нулевого байта в PHP?».
  8. ^ "UTF-8, формат преобразования ISO 10646" . Получено 19 сентября 2013 г. .
  9. ^ "Таблица символов Unicode/UTF-8" . Получено 13 сентября 2013 г. .
  10. ^ Кун, Маркус. "UTF-8 и Unicode FAQ" . Получено 13 сентября 2013 г.