Почему UTF-8 кодируется в 2 байта для символа U + 1xxxx? - PullRequest
1 голос
/ 21 октября 2019

Я пытаюсь понять, как C обрабатывает коды символов в Unicode. Я установил в качестве локали значение LC_ALL "fr_CA.UTF8", а затем ввел символ с wscanf() (как массив wchar_t ...). Затем я исследую каждый байт и нахожу что-то странное. Я ввел тройной ключ («?», скопированный с веб-страницы), то есть U + 1d11e. На самом деле это 3 байта, поэтому я ожидал получить 2 wchar_t. Я получил: 0x1e, 0xd1, 0x00, 0x00, последние два из которых являются нулевым окончательным символом. Вот мой код:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ( int argc, char* argv[] )
{  
    setlocale( LC_ALL, "fr_CA.utf8" ); 

    wchar_t input[256];

    wscanf( L"%ls", input);
    wprintf( L"%ls\n", input );

    wprintf( L"Length = %d\n", wcslen( input ) );
    wprintf( L"%d\n", (int)(input[0]&0x00ff) );
    wprintf( L"%d\n", (int)((input[0]&0xff00)>>8) );
    wprintf( L"%d\n", (int)(input[1]&0x00ff) );
    wprintf( L"%d\n", (int)((input[1]&0xff00)>>8) );
    wprintf( L"%d\n", (int)(input[2]&0x00ff) );
    wprintf( L"%d\n", (int)((input[2]&0xff00)>>8) );

    return 0;
}  

Я ожидал, что 0x1e, 0xd1, 0x01, 0x00, 0x00, 0x00 ...

Но у меня есть 0x1e, 0xd1, 0x00, 0x00. ..

Что меня удивляет, так это то, что wprintf( L"%ls\n", input ); на самом деле правильно печатает тройную клавишу ... Итак что позволяет различать символы U + 1D11E и U + D11E?

Кроме того, я запускаю свою программу в Konsole в Kubuntu 16.04 LTS, и я скомпилировал ее с gcc 6.5.0 ... если это имеет значение.

1 Ответ

6 голосов
/ 21 октября 2019

Вы увидите, что ожидаете, если вы распечатали байты, правильно составляющие значения wchar_t, или просто пропустили это и напечатали их значения, не пытаясь разбить их на байты:

wprintf(L"%x\n", (int)input[0]);
wprintf(L"%x\n", (int)input[1]);

И результат будет:

1d11e
0

То, как вы пытались это сделать, наводит на мысль, что у вас ошибочное впечатление, что значения wchar_t являются 16-битными и что существует такая вещь, как "мульти- wchar_t -character». Язык Си очень явно говорит о том, что такого нет. Реализации с 16-разрядным wchar_t являются неправильными (или по крайней мере не могут поддерживать Unicode вне BMP). Конечно, один довольно популярный - совершенно неправильный ...

Я только что заметил, что вы также упомянули UTF-8 в заголовке вашего вопроса, но контент не имеет ничего общего с представлением UTF-8. wchar_t - это (обычно; не обязательно) номер кода Unicode, эквивалентный UCS-4 (или UCS-2 в реализациях, которые поддерживают только BMP). В то время как многобайтовая кодировка локали почти наверняка должна быть UTF-8 для того, чтобы у вас был доступ к этому символу (хотя GB18030 также будет работать), UTF-8 не появится, если вы работаете со всеми вашими потоками настолько широкимисимвольные потоки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...