Обработка строки C - C string handling
Стандартная библиотека C |
---|
Общие темы |
Разные заголовки |
Язык программирования C имеет набор функций, реализующих операции со строками (символьными строками и байтовыми строками) в своей стандартной библиотеке . Поддерживаются различные операции, такие как копирование, конкатенация , токенизация и поиск. Для символьных строк стандартная библиотека использует соглашение о том, что строки заканчиваются нулем : строка из n символов представлена как массив из n + 1 элементов, последний из которых является NUL
символом (с числовым значением 0).
Единственная поддержка строк в собственном языке программирования заключается в том, что компилятор переводит строковые константы в кавычках в строки с завершающим нулем.
Определения
Строка определяется как непрерывная последовательность единиц кода, оканчивающаяся первой единицей нулевого кода (часто называемой единицей кода NUL ). Это означает, что строка не может содержать нулевую кодовую единицу, поскольку первая видимая отмечает конец строки. Длина строки является количество кодовых блоков перед блоком нулевой код. Память, занимаемая строкой, всегда на одну кодовую единицу больше, чем ее длина, так как пространство необходимо для хранения нулевого терминатора.
Как правило, термин строка означает строку, в которой кодовая единица имеет тип char
, который на всех современных машинах равен 8 битам. C90 определяет широкие строки, которые используют кодовую единицу типа wchar_t
, которая на современных машинах составляет 16 или 32 бита. Это было предназначено для Unicode, но вместо этого все чаще используется UTF-8 в обычных строках для Unicode.
Строки передаются функциям путем передачи указателя на первую единицу кода. Поскольку char*
и wchar_t*
относятся к разным типам, функции, обрабатывающие широкие строки, отличаются от функций, обрабатывающих обычные строки, и имеют другие имена.
Строковые литералы ( "text"
в исходном коде C) преобразуются в массивы во время компиляции. Результатом является массив кодовых единиц, содержащий все символы плюс завершающую нулевую кодовую единицу. В C90 L"text"
выдает широкую струну. Строковый литерал может содержать нулевую кодовую единицу (один из способов - вставить \0
в источник), но это приведет к тому, что строка закончится в этой точке. Остальная часть литерала будет помещена в память (с добавлением еще одной единицы нулевого кода в конце), но невозможно знать, что эти единицы кода были переведены из строкового литерала, поэтому такой исходный код не является строковым литералом.
Кодировки символов
Каждая строка заканчивается первым появлением единицы нулевого кода соответствующего вида ( char
или wchar_t
). Следовательно, байтовая строка ( char*
) может содержать символы, отличные от NUL в ASCII или любом расширении ASCII , но не символы в кодировках, таких как UTF-16 (даже если 16-битная кодовая единица может быть ненулевой, ее старший или младший байт может быть нуль). Кодировки, которые могут храниться в широких строках, определяются шириной wchar_t
. В большинстве реализаций wchar_t
это не менее 16 бит, поэтому все 16-битные кодировки, такие как UCS-2 , могут быть сохранены. Если wchar_t
32-битный, то 32-битные кодировки, такие как UTF-32 , могут быть сохранены. (Стандарт требует наличия «типа, который содержит любой широкий символ», что в Windows больше не выполняется, так как переход от UCS-2 к UTF-16.) C ++ 11 и C11 добавляют два типа с явной шириной char16_t
и char32_t
.
Кодировки переменной ширины могут использоваться как в байтовых, так и в широких строках. Длина строки и смещения измеряются в байтах wchar_t
, а не в «символах», что может сбить с толку начинающих программистов. UTF-8 и Shift JIS часто используются в строках байтов C, тогда как UTF-16 часто используется в строках шириной C, когда wchar_t
это 16 бит. Усечение строк символами переменной длины с использованием таких функций strncpy
может привести к появлению недопустимых последовательностей в конце строки. Это может быть небезопасно, если усеченные части интерпретируются кодом, который предполагает, что ввод действителен.
Поддержка литералов Unicode, таких как char foo[512] = "φωωβαρ";
(UTF-8) или wchar_t foo[512] = L"φωωβαρ";
(UTF-16 или UTF-32, в зависимости от wchar_t
), определяется реализацией и может потребовать, чтобы исходный код был в той же кодировке, особенно в тех случаях, char
когда компиляторы могут просто копировать все, что есть между кавычками. Некоторые компиляторы или редакторы потребуют вводить все символы, отличные от ASCII, как \xNN
последовательности для каждого байта UTF-8 и / или \uNNNN
для каждого слова UTF-16. Начиная с C11 (и C ++ 11) char foo[512] = u8"φωωβαρ";
доступен новый синтаксис литерала, который гарантирует UTF-8 для литерала строки байтов.
Обзор функций
Большинство функций, которые работают со строками C, объявлены в string.h
заголовке ( cstring
в C ++), тогда как функции, которые работают со строками шириной C, объявлены в wchar.h
заголовке ( cwchar
в C ++). Эти заголовки также содержат объявления функций, используемых для обработки буферов памяти; таким образом, название звучит неправильно.
Функции, объявленные в string.h
, чрезвычайно популярны, поскольку как часть стандартной библиотеки C они гарантированно работают на любой платформе, поддерживающей C. Однако с этими функциями существуют некоторые проблемы безопасности, такие как потенциальные переполнения буфера при неправильном использовании. , заставляя программистов отдавать предпочтение более безопасным и, возможно, менее переносимым вариантам, некоторые из которых перечислены ниже. Некоторые из этих функций также нарушают константную корректность , принимая const
указатель на строку и возвращая не const
указатель внутри строки. Чтобы исправить это, некоторые из них были разделены на две перегруженные функции в версии стандартной библиотеки для C ++.
В исторической документации термин «символ» часто использовался вместо «байта» для строк C, что заставляет многих полагать, что эти функции почему-то не работают для UTF-8 . Фактически, все длины определены в байтах, и это верно для всех реализаций, и эти функции работают как с UTF-8, так и с однобайтовыми кодировками. Документация BSD была исправлена, чтобы прояснить это, но документация POSIX, Linux и Windows по-прежнему использует «символ» во многих местах, где «байт» или «wchar_t» являются правильным термином.
Функции для обработки буферов памяти могут обрабатывать последовательности байтов, которые включают нулевой байт как часть данных. Имена этих функций обычно начинаются с mem
, а не с str
префикса.
Константы и типы
Имя | Примечания |
---|---|
NULL |
Макрос расширяется до константы нулевого указателя ; то есть константа, представляющая значение указателя, которое гарантированно не является действительным адресом объекта в памяти. |
wchar_t
|
Тип, используемый для кодовой единицы в широких строках, обычно беззнаковое 16-битное или 32-битное значение. Для этих кодовых единиц не указывается никакой конкретной интерпретации; стандарт C требует только, чтобы wchar_t был достаточно широким, чтобы содержать самый широкий набор символов среди поддерживаемых языковых стандартов системы . Теоретически wchar_t может иметь тот же размер, что и char , и, следовательно, не может содержать кодовые единицы UTF-32 или UTF-16 . |
wint_t
|
Целочисленный тип, который может содержать любое значение wchar_t, а также значение макроса WEOF. Этот тип неизменен интегральными акциями. Обычно 32-битное значение со знаком. |
mbstate_t
|
Содержит всю информацию о состоянии преобразования, требуемую от одного вызова функции к другому. |
Функции
Байтовая строка |
Широкая струна |
Описание | |
---|---|---|---|
Строковые манипуляции |
strcpy
|
wcscpy
|
Копирует одну строку в другую |
strncpy
|
wcsncpy
|
Записывает ровно n байтов, копируя из источника или добавляя нули | |
strcat
|
wcscat
|
Добавляет одну строку к другой | |
strncat
|
wcsncat
|
Добавляет не более n байтов из одной строки в другую | |
strxfrm
|
wcsxfrm
|
Преобразует строку в соответствии с текущим языковым стандартом | |
Струнный экспертиза |
strlen
|
wcslen
|
Возвращает длину строки |
strcmp
|
wcscmp
|
Сравнивает две строки ( трехстороннее сравнение ) | |
strncmp
|
wcsncmp
|
Сравнивает определенное количество байтов в двух строках | |
strcoll
|
wcscoll
|
Сравнивает две строки в соответствии с текущим языковым стандартом | |
strchr
|
wcschr
|
Находит первое вхождение байта в строку | |
strrchr
|
wcsrchr
|
Находит последнее вхождение байта в строку | |
strspn
|
wcsspn
|
Возвращает количество начальных байтов в строке, которые находятся во второй строке. | |
strcspn
|
wcscspn
|
Возвращает количество начальных байтов в строке, которых нет во второй строке. | |
strpbrk
|
wcspbrk
|
Находит в строке первое вхождение байта в наборе | |
strstr
|
wcsstr
|
Находит первое вхождение подстроки в строке | |
strtok
|
wcstok
|
Разбивает строку на токены | |
Разное |
strerror
|
N / A | Возвращает строку, содержащую сообщение, полученное из кода ошибки. |
Манипуляции с памятью |
memset
|
wmemset
|
Заполняет буфер повторяющимся байтом |
memcpy
|
wmemcpy
|
Копирует один буфер в другой | |
memmove
|
wmemmove
|
Копирует один буфер в другой, возможно, перекрывающийся, буфер | |
memcmp
|
wmemcmp
|
Сравнивает два буфера (трехстороннее сравнение) | |
memchr
|
wmemchr
|
Находит первое вхождение байта в буфер | |
|
Многобайтовые функции
Имя | Описание |
---|---|
mblen
|
Возвращает количество байтов в следующем многобайтовом символе. |
mbtowc
|
Преобразует следующий многобайтовый символ в широкий символ |
wctomb
|
Преобразует широкий символ в его многобайтовое представление |
mbstowcs
|
Преобразует многобайтовую строку в широкую строку |
wcstombs
|
Преобразует широкую строку в многобайтовую строку |
btowc
|
Если возможно, преобразовать однобайтовый символ в расширенный. |
wctob
|
Если возможно, преобразовать широкий символ в однобайтовый. |
mbsinit
|
Проверяет, представляет ли объект состояния начальное состояние |
mbrlen
|
Возвращает количество байтов в следующем многобайтовом символе для данного состояния. |
mbrtowc
|
Преобразует следующий многобайтовый символ в широкий символ при заданном состоянии |
wcrtomb
|
Преобразует широкий символ в его многобайтовое представление при заданном состоянии |
mbsrtowcs
|
Преобразует многобайтовую строку в широкую строку при заданном состоянии |
wcsrtombs
|
Преобразует широкую строку в многобайтовую строку при заданном состоянии |
Все эти функции принимают указатель на mbstate_tобъект, который вызывающий должен поддерживать. Первоначально это было предназначено для отслеживания состояний сдвига вмбкодировки, но современные, такие как UTF-8, в этом не нуждаются. Однако эти функции были разработаны исходя из предположения, чтоТуалеткодирование не является кодировкой с переменной шириной и, таким образом, предназначено для работы только с однимwchar_tза один раз, передавая его по значению, а не используя строковый указатель. Поскольку UTF-16 является кодировкой переменной ширины,mbstate_t был повторно использован для отслеживания суррогатных пар в широкой кодировке, хотя вызывающий должен по-прежнему обнаруживать и вызывать mbtowc дважды для одного персонажа.
Числовые преобразования
Байтовая строка |
Широкая струна |
Описание |
---|---|---|
atof
|
N / A | преобразует строку в значение с плавающей запятой ('atof' означает 'ASCII to float') |
atoi atol atoll
|
N / A | преобразует строку в целое число ( C99 ) ('atoi' означает 'ASCII в целое число') |
strtof ( C99 ) strtod strtold ( C99 )
|
wcstof ( C99 ) wcstod wcstold ( C99 )
|
преобразует строку в значение с плавающей запятой |
strtol strtoll
|
wcstol wcstoll
|
преобразует строку в целое число со знаком |
strtoul strtoull
|
wcstoul wcstoull
|
преобразует строку в беззнаковое целое число |
|
Стандартная библиотека C содержит несколько функций для числовых преобразований. Функции, которые работают с байтовыми строками, определены в stdlib.h
заголовке ( cstdlib
заголовок в C ++). Функции, которые работают с широкими строками, определены в wchar.h
заголовке ( cwchar
заголовок в C ++).
Эти strtoxxx
функции не сопзИте-правильно , так как они принимают const
указатель на строку и возвращают не- const
указателя в строке.
Кроме того, начиная с Нормативной поправки 1 (C95), atoxx
функции считаются включенными в strtoxxx
функции, по этой причине ни C95, ни какой-либо более поздний стандарт не предоставляют версии этих функций для расширенных символов. Аргумент против atoxx
заключается в том, что они не различают ошибку и ошибку 0
.
Популярные расширения
Имя | Платформа | Описание |
---|---|---|
bzero
|
POSIX , BSD | Заполняет буфер нулевыми байтами, не рекомендуется memset
|
memccpy
|
SVID , POSIX | копирует до указанного количества байтов между двумя областями памяти, которые не должны перекрываться, останавливаясь при нахождении данного байта. |
mempcpy
|
GNU | вариант memcpy возврата указателя на байт, следующий за последним записанным байтом
|
strcasecmp
|
POSIX, BSD | нечувствительные к регистру версии strcmp
|
strcat_s
|
Окна | вариант, strcat который проверяет размер целевого буфера перед копированием
|
strcpy_s
|
Окна | вариант, strcpy который проверяет размер целевого буфера перед копированием
|
strdup
|
POSIX | выделяет и дублирует строку |
strerror_r
|
POSIX 1, GNU | вариант strerror этого является поточно-ориентированным. Версия GNU несовместима с версией POSIX.
|
stricmp
|
Окна | нечувствительные к регистру версии strcmp
|
strlcpy
|
BSD, Solaris | вариант, strcpy который усекает результат, чтобы поместиться в целевой буфер
|
strlcat
|
BSD, Solaris | вариант, strcat который усекает результат, чтобы поместиться в целевой буфер
|
strsignal
|
POSIX: 2008 | возвращает строковое представление сигнального кода . Не потокобезопасный. |
strtok_r
|
POSIX | вариант, strtok который является потокобезопасным
|
Замены
Несмотря на хорошо налаженную необходимость замены strcat
и strcpy
с функциями , которые не допускают переполнения буфера, не принятый стандарт не возник. Частично это происходит из-за ошибочного мнения многих программистов на C о том, что strncat
и strncpy
имеют желаемое поведение; однако ни одна из функций не была разработана для этого (они предназначались для управления строковыми буферами фиксированного размера, заполненными нулями, формат данных, реже используемый в современном программном обеспечении), а поведение и аргументы не интуитивно понятны и часто неправильно записываются даже экспертами. программисты.
Наиболее популярной заменой являются strlcat
и strlcpy
функции, которые появились в OpenBSD 2.4 в декабре 1998. Эти функции всегда пишут одну NUL в буфер назначения, усечение результата , если это необходимо, и возвращает размер буфера , которые будут необходимы, что позволяет обнаруживать усечения и обеспечивает размер для создания нового буфера, который не будет усекаться. Их критиковали на основании якобы неэффективности, поощрения использования строк C (вместо какой-либо более совершенной альтернативной формы строк) и сокрытия других потенциальных ошибок. Следовательно, они не были включены в библиотеку GNU C (используемую программным обеспечением в Linux), хотя они реализованы в библиотеках C для OpenBSD, FreeBSD , NetBSD , Solaris , OS X и QNX , а также в альтернативных библиотеках C. для Linux, например, musl, представленный в 2011 году. Отсутствие поддержки библиотеки GNU C не помешало различным авторам программного обеспечения использовать ее и комплектовать замену среди других SDL , GLib , ffmpeg , rsync и даже внутри ядра Linux . Доступны реализации с открытым исходным кодом для этих функций.
Иногда используются memcpy
или memmove
, поскольку они могут быть более эффективными, чем то, strcpy
что они повторно не проверяют NUL (это менее верно для современных процессоров). Поскольку им в качестве параметра требуется длина буфера, правильная установка этого параметра может избежать переполнения буфера.
В рамках своего жизненного цикла разработки системы безопасности 2004 года Microsoft представила семейство «безопасных» функций, включая strcpy_s
и strcat_s
(наряду со многими другими). Эти функции были стандартизированы с некоторыми незначительными изменениями как часть необязательного C11 (Приложение K), предложенного ISO / IEC WDTR 24731. Эти функции выполняют различные проверки, в том числе, является ли строка слишком длинной для размещения в буфере. Если проверка завершается неудачно, вызывается заданная пользователем функция «обработчик ограничения времени выполнения», которая обычно прерывает выполнение программы. Некоторые функции выполняют деструктивные операции перед вызовом обработчика ограничения времени выполнения; например, strcat_s
устанавливает в качестве места назначения пустую строку, что может затруднить восстановление после ошибок или их отладку. Эти функции вызвали серьезную критику, поскольку изначально они были реализованы только в Windows, и в то же время Microsoft Visual C ++ начал выдавать предупреждающие сообщения, предлагающие программистам использовать эти функции вместо стандартных. Некоторые предполагают, что это попытка Microsoft заблокировать разработчиков своей платформой. Хотя реализации этих функций с открытым исходным кодом доступны, эти функции отсутствуют в общих библиотеках Unix C. Опыт работы с этими функциями показал значительные проблемы с их внедрением и ошибки в использовании, поэтому предлагается исключить Приложение K в следующей редакции стандарта C. Использование memset_s
также было предложено в качестве способа избежать нежелательных оптимизаций компилятора.
Смотрите также
- Синтаксис C § Строки - синтаксис исходного кода, включая escape-последовательности с обратной косой чертой
- Строковые функции
Примечания
использованная литература
внешние ссылки
- Быстрый memcpy на C , несколько примеров кодирования C для разных типов архитектур команд ЦП