C Unicode: Как применить исправление DR488 стандартной поправки C11 к стандартной функции C11 c16rtomb()?

Вопрос:

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

В С11, как опубликовано, в отличие от mbrtoc16, которая преобразует многобайтовую переменную ширину (например, UTF-8) в 16-битное (например, UTF-16) кодирование переменной ширины, эта функция может преобразовывать только 16-битную кодировку одного блока, то есть она не может преобразовывать UTF-16 до UTF-8, несмотря на то, что это было первоначальное намерение этой функции. Это было исправлено в отчете о дефектах после С11 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://stackru.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 ответ

Решение

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

Пример на идеоне

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

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

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

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

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