Intereting Posts
Нечетная проблема с указателем при реализации связанного списка Как скомпилировать программу Linux C для запуска на другой машине Linux? Ошибка сегментации программы сборки GAS (запись в автоматическую переменную) Как использовать MPI_Gatherv для сбора строк различной длины из разных процессоров, включая главный узел? Как указать формат драйвера доступа ODBC при создании базы данных Спецификатор формата% a для printf () в C Захват и замена функции экспорта в загруженном ELF (разделяемая библиотека .so) Переменная массива Cuda Shared Memory Что означает «a ## b» в C? Как преобразовать unsigned long в строку Вызов командной строки из программы C Does LeaveCriticalSection () удаляет кэшированные переменные в память? Храните числовые данные в массиве char в переменной INTEGER в VC ++. C Вставить элемент при начале связанного списка Я чувствую путаницу в ошибке шины в строке (C)

Отображение широких символов с printf

Я пытаюсь понять, как printf работает с широкими символами ( wchar_t ).

Я сделал следующие примеры кода:

Пример 1:

 #include  #include  int main(void) { wchar_t *s; s = (wchar_t *)malloc(sizeof(wchar_t) * 2); s[0] = 42; s[1] = 0; printf("%ls\n", s); free(s); return (0); } 

выход :

 * 

Здесь все хорошо: мой персонаж ( * ) отображается правильно.

Пример 2:

Я хотел показать другой характер. В моей системе wchar_t кажется закодированным на 4 байта. Поэтому я попытался отобразить следующий символ: É

 #include  #include  int main(void) { wchar_t *s; s = (wchar_t *)malloc(sizeof(wchar_t) * 2); s[0] = 0xC389; s[1] = 0; printf("%ls\n", s); free(s); return (0); } 

Но на этот раз выхода нет, я попытался использовать множество значений из раздела «кодирование» (см. Предыдущую ссылку) для s[0] (0xC389, 201, 0xC9) … Но я никогда не получаю символ É . Я также попытался использовать %S вместо %ls .

Если я попытаюсь вызывать printf следующим образом: printf("\n", s) единственный напечатанный символ – '<' , экран усечен.

Почему у меня такая проблема? Как мне это сделать?

Почему у меня такая проблема?

Убедитесь, что вы проверили errno и возвращаемое значение printf !

 #include  #include  #include  int main(void) { wchar_t *s; s = (wchar_t *) malloc(sizeof(wchar_t) * 2); s[0] = 0xC389; s[1] = 0; if (printf("%ls\n", s) < 0) { perror("printf"); } free(s); return (0); } 

См. Вывод:

 $ gcc test.c && ./a.out printf: Invalid or incomplete multibyte or wide character 

Как исправить

Прежде всего, языковой стандарт по умолчанию программы C - это C (также известный как POSIX ), который является ASCII-only. Вам нужно будет добавить вызов setlocale , в частности setlocale(LC_ALL,"") .

Если переменные среды LC_ALL , LC_CTYPE или LANG не установлены, чтобы разрешить UTF-8, когда они пусты, вам нужно будет явно выбрать локаль. setlocale(LC_ALL, "C.UTF-8") работает на большинстве систем - C является стандартным, а подмножество UTF-8 C обычно реализуется.

 #include  #include  #include  #include  int main(void) { wchar_t *s; s = (wchar_t *) malloc(sizeof(wchar_t) * 2); s[0] = 0xC389; s[1] = 0; setlocale(LC_ALL, ""); if (printf("%ls\n", s) < 0) { perror("printf"); } free(s); return (0); } 

См. Вывод:

 $ gcc test.c && ./a.out 쎉 

Причина, по которой напечатан неправильный символ, заключается в том, что wchar_t представляет собой широкий символ (например, UTF-32), а не многобайтовый символ (например, UTF-8). Обратите внимание, что wchar_t всегда имеет ширину в 32 бита в библиотеке GNU C, но стандарт C не требует этого. Если вы инициализируете символ с использованием UTF-32BE (то есть 0x000000C9 ), то он печатает правильно:

 #include  #include  #include  #include  int main(void) { wchar_t *s; s = (wchar_t *) malloc(sizeof(wchar_t) * 2); s[0] = 0xC9; s[1] = 0; setlocale(LC_ALL, ""); if (printf("%ls\n", s) < 0) { perror("printf"); } free(s); return (0); } 

Выход:

 $ gcc test.c && ./a.out É 

Обратите внимание, что вы также можете установить переменные среды LC (locale) через командную строку:

 $ LC_ALL=C.UTF-8 $ ./a.out É 

Одна из проблем заключается в том, что вы пытаетесь кодировать UTF-8, которая является однобайтовой схемой кодирования, как многобайтовая кодировка. Для UTF-8 используется простой char .

Также обратите внимание, что, поскольку вы пытаетесь объединить последовательность UTF-8 в многобайтовый тип, у вас есть проблемы с порядком (байтом) (в памяти 0xC389 может храниться как 0x89 и 0xC3 , в этом порядке). И что компилятор подпишет – также расширьте свой номер (если sizeof(wchar_t) == 4 и вы посмотрите на s[0] в отладчике, это может быть 0xFFFFC389 ).

Другая проблема – это терминал или консоль, которые вы используете для печати. Может быть, это просто не поддерживает UTF-8 или другие кодировки, которые вы пробовали?