Рассмотрим следующую простую программу, которая использует printf()
для печати широкой строки, если она запускается без аргументов командной строки, и wprintf()
в противном случае:
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
const wchar_t hello1[] = L"تحية طيبة";
const wchar_t hello2[] = L"Tervehdys";
int main(int argc, char *argv[])
{
if (!setlocale(LC_ALL, ""))
fprintf(stderr, "Warning: Current locale is not supported by the C library.\n");
if (argc <= 1) {
printf("printf 1: %ls\n", hello1);
printf("printf 2: %ls\n", hello2);
} else {
wprintf(L"wprintf: %ls\n", hello1);
wprintf(L"wprintf: %ls\n", hello2);
}
return EXIT_SUCCESS;
}
Использование библиотеки GNU C и любых другихЯзык UTF-8:
$ ./example
printf 1: تحية طيبة
printf 2: Tervehdys
$ ./example wide
wprintf: تحية طيبة
wprintf: Tervehdys
, т. Е. Оба дают одинаковый вывод.Однако, если мы запустим пример в локали C / POSIX (которая поддерживает только ASCII), мы получим
$ LANG=C LC_ALL=C ./example
printf 1: printf 2: Tervehdys
, т. Е. Первый printf()
остановился на первом не-ASCII-символе (и поэтомувторой printf()
, напечатанный в той же строке);
$ LANG=C LC_ALL=C ./example wide
wprintf: ???? ????
wprintf: Tervehdys
т.е. wprintf()
заменяет широкие символы, которые не могут быть представлены в кодировке, используемой текущей локалью, на ?
.
Итак, если мы рассмотрим библиотеку GNU C (которая демонстрирует такое поведение), то мы должны сказать да, printf заботится о локали , хотя на самом деле она в основном заботится о наборе символов, используемом локалью,а не локаль как таковая:
printf()
остановится при попытке печати широких строк, которые не могут быть представлены текущим набором символов (как определено локалью).
wprintf()
вместо этого выведет вопросительные знаки для этих символов.
libc6-2.23-0ubuntu10 на x86-64 (amd64) делает некоторые замены для многобайтовых символов в строке формата printf, но многобайтовыхсимволы в строках, напечатанные с %s
, печатаются как есть.Это означает, что немного сложно точно сказать, что печатается, и когда printf()
отказывается от первого многобайтового или широкого символа, который он не может преобразовать, или просто печатает как есть.
Однако wprintf()
довольно твердое тело(Это также может задушить, если вы попытаетесь напечатать узкие строки с многобайтовыми символами, которые не могут быть представлены в наборе символов, используемом в текущей локали, но для широких строк это, кажется, работает очень хорошо.)
Обратите внимание, чтоБиблиотеки POSIX.1 C также предоставляют iconv_open()
, iconv()
и iconv_close()
для преобразования строк, а также mbstowcs()
и wcstombs()
для преобразования между широкими и узкими / многобайтовыми строками.Вы также можете использовать asprintf()
для создания динамически выделяемой узкой строки из строк узких и / или широких символов (%s
и %ls
соответственно).