Используя setlocale, мы можем указать кодировку строк, которые читаются из входных данных, но относится ли это и к строковым литералам?
Нет.Строковые литералы используют набор символов выполнения , который определяется вашим компилятором во время компиляции.
Набор символов выполнения не обязательно должен совпадать с исходный набор символов , набор символов, используемый в исходном коде.Компилятор C отвечает за перевод и должен иметь параметры для выбора / определения их.Значение по умолчанию зависит от компилятора, но в Linux и в большинстве современных систем POSIXy обычно используется UTF-8.
Следующий фрагмент кода мне подходит.Но разве это не работает только из-за совпадения?
Пример работает, потому что все наборы символов вашей локали, исходный набор символов и набор символов выполнения, использованные при создании двоичного файла, все происходятбыть UTF-8.
Как это сделать правильно?
Два варианта.Одним из них является использование широких символов и строковых литералов.Другой - использовать UTF-8 везде .
Для широкого ввода и вывода, см., Например, этот пример в другом ответе здесь.
Doобратите внимание, что getwline()
и getwdelim()
не в POSIX.1, а в C11 Приложении K. Это означает, что они являются необязательными, и на момент написания этой статьи вообще не были широко доступны.Таким образом, вместо этого рекомендуется пользовательская реализация около fgetwc()
.(Один из них, основанный на fgetws()
, wcslen()
и / или wcscspn()
, не сможет правильно обрабатывать встроенные нули, L'\0'
.)
В типичной программе с широким вводом / выводом вам нужно только mbstowcs()
для преобразования аргументов командной строки и переменных среды в широкие строки.
Использование UTF-8 везде - это также совершенно правильный практический подход, по крайней мере, если он хорошо документирован, так что пользователи знают, как вводить и выводить строки UTF-8, а разработчики знают, что их компилятор C использует UTF-8 в качестве набора символов выполнения при компиляции этих двоичных файлов.
Ваша программа может даже использовать, например,
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Your C library does not support your current locale.\n");
if (strcmp("UTF-8", nl_langinfo(CODESET)))
fprintf(stderr, "Warning: Your locale does not use the UTF-8 character set.\n");
, чтобы проверить, что текущий языковой стандарт использует UTF-8.
У меня естьИспользуются оба подхода в зависимости от обстоятельств.Трудно сказать, какой из них является более переносимым на практике, потому что, как обычно, оба прекрасно работают на не-Windows ОС без проблем.