Трудно сказать, с чего начать, поскольку в игре много предположений.
В C, как мы его знаем и любим, есть тип данных 'char'. Во всех широко используемых реализациях этот тип данных содержит 8-битный байт.
В языке, в отличие от любых библиотечных функций, которые вы используете, эти вещи являются просто целыми числами, дополняющими два. У них нет семантики «характера».
Как только вы начинаете вызывать функции из стандартной библиотеки с именами 'str' или 'is' (например, strcmp, isalnum), вы имеете дело с семантикой символов.
Программы на C должны были справиться с гигантским беспорядком, состоящим из семантики символов, до изобретения Unicode. Различные организации изобрели очень большое количество стандартов кодирования. Некоторые из них по одному символу на байт. Некоторые из них являются несколькими символами на байт. В некоторых всегда можно спросить if (charvalue == 'a')
. В других случаях это может привести к неправильному ответу из-за многобайтовой последовательности.
Почти в каждой современной среде семантика стандартной библиотеки определяется настройкой локали.
Откуда приходит UTF-8? Некоторое время назад был создан консорциум Unicode, чтобы попытаться навести порядок во всем этом хаосе. Unicode определяет символьное значение (в 32-битном символьном пространстве) для многих, многих, многих символов. Цель состоит в том, чтобы охватить все символы практического использования.
Если вы хотите, чтобы ваш код работал на английском, арабском, китайском и шумерской клинописи, вам нужна семантика символов Юникода, а не написание кода, который приглушается и использует различные кодировки символов.
Концептуально, самый простой способ сделать это - использовать 32-битные символы (UTF-32), и, таким образом, у вас будет один элемент на логический символ. Большинство людей решили, что это нецелесообразно. Обратите внимание, что в современных версиях gcc тип данных wchar_t является 32-разрядным символом, но Microsoft Visual Studio не соглашается, определяя этот тип данных как 16-разрядные значения (UTF-16 или UCS-2, в зависимости от ваша точка зрения).
Большинство не-Windows C программ слишком сильно вложены в 8-битные символы, чтобы их можно было изменить. Итак, стандарт Unicode включает в себя UTF-8, представление текста Unicode в виде последовательности 8-битных байтов. В UTF-8 каждый логический символ имеет длину от 1 до 4 байтов. Основные символы ISO-646 («ascii») «играют сами», поэтому простые операции над простыми символами работают, как и ожидалось.
Если ваша среда включает локали для UTF-8, тогда вы можете установить локаль на локаль UTF-8, и все стандартные функции lib будут просто работать. Если ваша среда не включает локали для UTF-8, вам понадобится дополнение, например ICU или ICONV.
До сих пор все это обсуждение касалось данных, хранящихся в переменных в памяти. Вы также должны иметь дело с чтением и написанием этого. Если вы назовете open(2)
или моральный эквивалент Windows, вы получите необработанные байты из файла. Если их нет в UTF-8, вам придется конвертировать их, если вы хотите работать в UTF-8.
Если вы позвоните fopen(3)
, тогда стандартная библиотека может попытаться оказать вам услугу и выполнить преобразование между ее идеей кодировки файлов по умолчанию и ее идеей о том, что вы хотите в памяти. Если вам нужно, например, запустить программу в системе в греческом языке и прочитать файл на китайском языке в Big5, вам нужно быть осторожным с параметрами, которые вы передаете fopen, или вы, возможно, захотите избегай это. И вам понадобится ICONV или ICU для конвертации в UTF-8 и обратно.
Ваш вопрос упоминает «входные строки». Это может быть несколько вещей. В локали UTF-8 argv
будет UTF-8. Файловым дескриптором 0 будет UTF-8. Если оболочка не работает в локали UTF-8, и вы вызываете setlocale
для локали UTF-8, вы не обязательно получите значения в UTF-8 в argv
. Если вы подключите содержимое файла к дескриптору файла, вы получите все, что находится в файле, в любой кодировке, в которой оно находится.