Как обрабатывать char16_t или char32_t с printf и scanf на C?

Если я напишу:

      char a = 'A';
printf("%x %c", a, a);

он выдаст на выходе «41 А». Аналогично, когда я пишу

      char32_t c = U'🍌';
printf("%x %c", c, c);  //even tried %lc and %llc

он выдаст на выходе «1f34c L» вместо ожидаемого «1f34c 🍌»!

Здесь что-то не так? Как я могу напечатать символы char16_t и char32_t на stdout?

Кроме того, какой описатель формата я должен использовать для получения ввода char16_t / char32_t от scanf?

      char32_t c;
scanf("%c", &c); //🍌
printf("%x %c", c, c);

это даст результат "f0 ".

2 ответа

и ничего особенного. Они действительно просто uint_least16_tа также uint_least32_t. У них нет такой большой поддержки. Единственное, для чего они используются, в основном uа также Uлитералы. Они могут быть не UTF-16 и не UTF-32 - проверьте __STDC_UTF_16__а также __STDC_UTF_32__макросы, прежде чем предположить, что они есть. Только самые основные функции преобразования входят в стандартную комплектацию. В стандарте есть только функции конвертации или в многобайтовую кодировку и обратно. Чтобы сделать с ними что- то еще, вы должны реализовать это самостоятельно.

Язык C действительно имеет две кодировки - многобайтовое представление символов, зависящее от локали , и широкое представление символов.

Что-то здесь не так?

Символ, который вы набрали в исходном файле , интерпретируется компилятором как значение, специфичное для конкретной реализации. Gcc сделает UTF-8, то препроцессор gcc сдвинет значения влево, поэтому ''равно (int)0xF09F8D8C на gcc — поведение многосимвольных литералов 'something'определяется реализацией. Затем значение этого символа присваивается . Это вовсе не значение UTF-32.

Как я могу вывести символы char16_t и char32_t на стандартный вывод?

Преобразуйте их в многобайтовую строку. Затем просто распечатайте его с помощью %s.

      #include <stdlib.h>
#include <uchar.h>
#include <stdio.h>
#include <wchar.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
int main() {
    setlocale(LC_ALL, "en_US.UTF-8");
    char32_t c = U'';
    char buf[MB_LEN_MAX + 1] = {0};
    mbstate_t ps;
    memset(&ps, 0, sizeof(ps));
    c32rtomb(buf, c, &ps);
    printf("%s\n", buf);
}

Печать данных зависит от локали , так как печать выполняется в локали, указанной пользователем. Локаль по умолчанию Cи не имеет поддержки UTF. Итак, сначала вам нужно установить локаль на что-то совместимое с utf. Тогда позвони c32rtomb. Обратите внимание, что поток выбирает кодировку при первой печати в glibc- обязательно позвоните setlocale прежде чем делать что-либо с потоком, с которым вы хотите работать.

какой спецификатор формата я должен использовать для получения ввода char16_t / char32_t из scanf?

Нет, нет. Вы должны использовать wchar_tили простой charстроки для чтения символов от пользователя в кодировке, указанной в его локали. Затем вы можете конвертировать в/из char16_tа также char32_tЕсли хочешь. Если вы хотите специально читать символы UTF-32, вам нужно написать это самостоятельно, чтобы убедиться, что ваш код читает UTF-32персонажи. Я рекомендую либунистринг.

я дал значение в HEXформат symbol = 0x0001F34Cесть и другие способы решить эту проблему, вот как я знаю, проверьте следующий код в c, мы не можем напечатать символ, используя %cили просто printf вот объясните, зачем использовать wchar_t вместо char charимеют кодировку UTF-8, а wchar_t имеют UTF-32, что увеличивает его диапазон

      #include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
    setlocale(LC_CTYPE, "");
    wchar_t symbol = 0x0001F34C;
    wprintf(L"%x %lc\n",symbol,symbol);
}
      output: 1f34c 

проверьте следующую ссылку Печать символа Unicode в C , UNICODE банана emoji , char32_t

Другие вопросы по тегам