C Unicode: Как применить исправление DR488 стандартной поправки C11 к стандартной функции C11 c16rtomb ()? - PullRequest
0 голосов
/ 05 ноября 2018

Вопрос:

Как упомянуто на справочной странице C для функции, c16rtomb, из CPPReference , в разделе Примечания :

В опубликованном C11, в отличие от mbrtoc16, который преобразует многобайтовое кодирование переменной ширины (например, UTF-8) в 16-битное кодирование переменной ширины (например, UTF-16), эта функция может преобразовывать только одну единицу 16-битное кодирование, означающее, что оно не может конвертировать UTF-16 в UTF-8, несмотря на то, что это было первоначальным намерением этой функции. Это было исправлено в отчете о дефектах после C11 DR488 .

И ниже этого отрывка, на странице ссылок C приведен пример исходного кода со следующим предложением над ним:

Примечание: в этом примере предполагается, что применено исправление для отчета о дефекте 488.

Эта фраза подразумевает, что есть способ взять DR488 и каким-то образом "применить" исправление к стандартной функции C11, c16rtomb.

Я хотел бы знать, как применить исправление для GCC. Поскольку мне кажется, что исправление уже применено к Visual Studio 2017 Visual C ++, начиная с версии 141.

Поведение, наблюдаемое в GCC при отладке кода в GDB, согласуется с тем, что было обнаружено в DR488, следующим образом:

Раздел 7.28.1 описывает функцию c16rtomb (). В частности, в нем говорится: «Когда c16 не является допустимым широким символом, возникает ошибка кодирования». «широкий символ» определен в разделе 3.7.3 как «значение, представляемое объектом типа wchar_t, способным представлять любой символ в текущей локали». Эта формулировка, по-видимому, подразумевает, что, например, для общих случаев (например, реализация, которая определяет __STDC_UTF_16__ и программа, которая использует локаль UTF-8), c16rtomb () вернет -1, когда встретит символ, который закодирован как несколько char16_t (для UTF-16 широкий символ может быть закодирован как суррогатная пара, состоящая из двух char16_t). В частности, c16rtomb () не сможет обрабатывать строки, сгенерированные mbrtoc16 ().

Текст, выделенный жирным шрифтом, соответствует описанному поведению.

Исходный код:

#include <stdio.h>
#include <uchar.h>

#define __STD_UTF_16__

int main() {
    char16_t* ptr_string = (char16_t*) u"我是誰";

    //C++ disallows variable-length arrays. 
    //GCC uses GNUC++, which has a C++ extension for variable length arrays.
    //It is not a truly standard feature in C++ pedantic mode at all.
    //https://stackoverflow.com/questions/40633344/variable-length-arrays-in-c14
    char buffer[64];
    char* bufferOut = buffer;

    //Must zero this object before attempting to use mbstate_t at all.
    mbstate_t multiByteState = {};

    //c16 = 16-bit Characters or char16_t typed characters
    //r = representation
    //tomb = to Multi-Byte Strings
    while (*ptr_string) {
        char16_t character = *ptr_string;
        size_t size = c16rtomb(bufferOut, character, &multiByteState);
        if (size == (size_t) -1)
            break;
        bufferOut += size;
        ptr_string++;
    }

    size_t bufferOutSize = bufferOut - buffer;
    printf("Size: %zu - ", bufferOutSize);
    for (int i = 0; i < bufferOutSize; i++) {
        printf("%#x ", +(unsigned char) buffer[i]);
    }

    //This statement is used to set a breakpoint. It does not do anything else.
    int debug = 0;
    return 0;
}

Вывод из Visual Studio:

Size: 9 - 0xe6 0x88 0x91 0xe6 0x98 0xaf 0xe8 0xaa 0xb0

Выход из GCC:

Size: 0 -

1 Ответ

0 голосов
/ 06 ноября 2018

В Linux вы сможете исправить это с помощью вызова setlocale(LC_ALL, "en_US.utf8");

Пример использования ideone

Эта функция будет выполнять следующие действия, как указано в Документация Microsoft :

Преобразование широкого символа UTF-16 в многобайтовый символ в текущей локали .

Документация POSIX аналогична. __STD_UTF_16__, похоже, не влияет ни на один из компиляторов. Предполагается указать кодировку для источника, которая должна быть UTF16. Не указывается кодировка для пункта назначения.

Это документация Windows, которая кажется более противоречивой, потому что, кажется, подразумевает, что setlocale необходимо, или преобразование в кодовую страницу ANSI является опцией

...