Язык программирования C имеет набор функций реализация операций с строками (символьными строками и байтовыми строками) в своей стандартной библиотеке. Поддерживаются различные операции, такие как копирование, конкатенация, токенизация и поиск. Для символьных строк стандартная библиотека использует соглашение о том, что строки завершаются нулем : строка из n символов представлена как массив из n + 1 элементов, последний из которых символ "NUL".
Единственная поддержка строк в собственно языке программирования заключается в том, что компилятор переводит заключенные в кавычки строковые константы в строки с завершающим нулем.
Строка определяется как непрерывная последовательность единицы кода, заканчивающиеся первой единицей нулевого кода (часто называемой единицей кода NUL). Это означает, что строка не может содержать нулевую кодовую единицу, так как первая видимая отмечает конец строки. Длина строки - это количество единиц кода до единицы нулевого кода. Память, занимаемая строкой, всегда на одну кодовую единицу больше, чем длина, так как пространство необходимо для хранения нулевого терминатора.
Как правило, термин строка означает строку, в которой кодовая единица имеет тип char
, что на всех современных машинах составляет ровно 8 бит. C90 определяет широкие строки, в которых используется кодовая единица типа wchar_t
, которая на современных машинах составляет 16 или 32 бита. Это было предназначено для Unicode, но вместо этого все чаще используется UTF-8 в обычных строках для Unicode.
Строки передаются функциям путем передачи указателя на первую единицу кода. Поскольку char *
и wchar_t *
относятся к разным типам, функции, обрабатывающие широкие строки, отличаются от функций, обрабатывающих обычные строки, и имеют разные имена.
Строковые литералы («текст»
в исходном коде C) преобразуются в массивы во время компиляции. Результатом является массив кодовых единиц, содержащий все символы плюс завершающую нулевую кодовую единицу. В C90 L «текст»
производит широкую строку. Строковый литерал может содержать нулевой кодовый блок (один из способов - поместить \ 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
, может создавать недопустимые последовательности в конце строки. Это может быть небезопасно, если усеченные части интерпретируются кодом, который предполагает, что ввод действителен.
Поддержка литералов Юникода, таких как 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
и возвращая указатель не- const
внутри строки. Чтобы исправить это, некоторые из них были разделены на две перегруженные функции в версии стандартной библиотеки C ++.
В исторической документации термин «символ» часто использовался вместо «байта» для строк C, что заставляет многих полагать, что эти функции каким-то образом не работают для UTF-8. Фактически, все длины определены в байтах, и это верно для всех реализаций, и эти функции работают как с UTF-8, так и с однобайтовыми кодировками. Документация BSD была исправлена, чтобы прояснить это, но документация POSIX, Linux и Windows по-прежнему использует «символ» во многих местах, где «байт» или «wchar_t» являются правильным термином.
Функции для обработки буферов памяти могут обрабатывать последовательности байтов, которые включают нулевой байт как часть данных. Имена этих функций обычно начинаются с mem
, в отличие от префикса str
.
Name | Примечания |
---|---|
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 | Преобразует строку в соответствии с текущим языковым стандартом | |
String. review | strlen | wcslen | Возвращает длину строки |
strcmp | wcscmp | Сравнивает две строки (трехстороннее сравнение ) | |
strncmp | wcsncmp | Сравнивает определенное количество байтов в двух строках | |
strcoll | wcscoll | Сравнивает две строки в соответствии с текущей локалью | |
strchr | wcschr | Находит первое вхождение байта в строку | |
strrchr | wcsrchr | Находит последнее вхождение байта в строку | |
strspn | wcsspn | Возвращает номер инициализации ial bytes в строке, которые находятся во второй строке | |
strcspn | wcscspn | Возвращает количество начальных байтов в строке, которых нет во второй строке | |
strpbrk | wcspbrk | Находит в строке первое вхождение байта в наборе | |
strstr | wcsstr | Находит первое вхождение подстроки в строке | |
strtok | wcstok | Разбивает строку на токены | |
Разное | strerror | Н / Д | Возвращает строку, содержащую сообщение, полученное из кода ошибки |
Операция с памятью. | memset | wmemset | Заполняет буфер повторяющимся байтом |
memcpy | wmemcpy | Копирует один буфер в другой | |
memmove | wmemmove | Копирует один буфер в другой, возможно перекрывающийся, буфер | |
memcmp | wmemcmp | Сравнивает два буфера (трехстороннее сравнение) | |
memchr | wmemchr | Находит первое вхождение байта в буфер | |
|
Имя | Описание |
---|---|
mblen | Возвращает количество байтов в следующем многобайтовом символе |
mbtowc | Преобразует следующий многобайтовый символ в широкий символ |
wctomb | Преобразует широкий символ в его многобайтовое представление |
mbstowcs | Преобразует многобайтовую строку в широкую строку |
wcstombs | Преобразует широкую строку в многобайтовую строку |
btowc | Преобразует однобайтовую строку. байтовый символ в широкий символ, если возможно |
wctob | Преобразование широкого символа в однобайтовый символ, если возможно |
mbsinit | Проверяет, представляет ли объект состояния начальное состояние |
mbrlen | Возвращает количество байтов в следующем многобайтовом символе при заданном состоянии |
mbrtowc | Преобразует следующий многобайтовый символ в широкий символ при данном состоянии |
wcrtomb | Преобразует широкий символ в его многобайтовое представление при заданном состоянии |
mbsrtowcs | Преобразует многобайтовую строку в широкую строку с заданным состоянием |
wcsrtombs | Преобразует широкую строку в multib yte string, заданное состояние |
Все эти функции принимают указатель на объект mbstate_t, который вызывающий должен поддерживать. Первоначально это было предназначено для отслеживания состояний сдвига в кодировках mb, но современные кодировки, такие как UTF-8, в этом не нуждаются. Однако эти функции были разработаны в предположении, что кодировка wcне является кодировкой переменной ширины и, таким образом, предназначены для работы только с одним wchar_tза раз., передавая его по значению, а не используя строковый указатель. Поскольку UTF-16 является кодировкой переменной ширины, mbstate_tбыл повторно использован для отслеживания суррогатных пар в широкой кодировке, хотя вызывающий должен по-прежнему обнаруживать и вызывать mbtowcдважды для один символ.
Байт. строка | Широкая. строка | Описание |
---|---|---|
atof | Н / Д | преобразует строку в значение с плавающей запятой ('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 содержит se обычные функции для числовых преобразований. Функции, работающие с байтовыми строками, определены в заголовке stdlib.h
(заголовок cstdlib
в C ++). Функции, работающие с широкими строками, определены в заголовке wchar.h
(заголовок cwchar
в C ++).
Функции strtoxxx
не являются const-corrective, поскольку они принимают строковый указатель 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 | Windows | вариант strcat , который проверяет место назначения размер буфера перед копированием |
strcpy_s | Windows | вариант strcpy , который проверяет размер целевого буфера перед копированием |
strdup | POSIX | выделяет и дублирует строку |
strerror_r | POSIX 1, GNU | вариант strerror , который является потокобезопасным. Версия GNU несовместима с версией POSIX. |
stricmp | Windows | нечувствительные к регистру версии 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 заблокировать разработчиков своей платформой. Хотя реализации этих функций с открытым исходным кодом доступны, эти функции отсутствуют в общих библиотеках C для Unix. Опыт использования этих функций показал значительные проблемы с их внедрением и ошибки в использовании, поэтому предлагается исключить Приложение K для следующей версии стандарта C. Использование memset_s
также было предложено как способ избежать нежелательной оптимизации компилятора.
В Викиучебнике Программирование на C есть страница по теме: Программирование на C / Строки |