Строка с завершающим нулем - Null-terminated string

В компьютерное программирование, а строка с завершающим нулем это строка символов хранится как множество содержащий символы и оканчивающийся нулевой символ ('\0', называется NUL в ASCII ). Альтернативные названия C строка, который относится к Язык программирования C и ASCIIZ (хотя C может использовать кодировки, отличные от ASCII).

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

История

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

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

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

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

Ограничения

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

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

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

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

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

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

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

Улучшения

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

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

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

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

  1. ^ Деннис М. Ричи (1993). [Развитие языка Си]. Proc. 2-я конференция по истории языков программирования.
  2. ^ Камп, Поул-Хеннинг (25 июля 2011 г.), "Самая дорогая однобайтовая ошибка", Очередь ACM, 9 (7), ISSN  1542-7730, получено 2 августа 2011
  3. ^ Щенок дождевого леса (9 сентября 1999 г.). "Проблемы Perl CGI". Журнал Phrack. artofhacking.com. 9 (55): 7. Получено 3 января 2016.
  4. ^ https://security.stackexchange.com/questions/48187/null-byte-injection-on-php
  5. ^ «UTF-8, формат преобразования ISO 10646». Получено 19 сентября 2013.
  6. ^ "Таблица Unicode / UTF-8 символов". Получено 13 сентября 2013.
  7. ^ Кун, Маркус. «Часто задаваемые вопросы по UTF-8 и Unicode». Получено 13 сентября 2013.