Вопрос:
Как упомянуто на справочной странице 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 -