Какая кодировка конвертирует c32rtomb?
Функции c32rtomb
и mbrtoc32
из <cuchar>
/<uchar.h>
описаны в C Unicode TR (проект) как выполнение преобразований между UTF-32 1 и "многобайтовые символы".
(...) Если s
не является нулевым указатель, функция c32rtomb
определяет количество байтов, необходимых для представления многобайтовый символ, который соответствует широкому символу, заданному c32
(включая любые последовательности сдвигов) и сохраняет многобайтовое представление символа в массив, на первый элемент которого указан s
. (...)
Что это за "многобайтовое представление символов"? Меня действительно интересует поведение следующей программы:
#include <cassert>
#include <cuchar>
#include <string>
int main() {
std::u32string u32 = U"this is a wide string";
std::string narrow = "this is a wide string";
std::string converted(1000, '\0');
char* ptr = &converted[0];
std::mbstate_t state {};
for(auto u : u32) {
ptr += std::c32rtomb(ptr, u, &state);
}
converted.resize(ptr - &converted[0]);
assert(converted == narrow);
}
Утверждается ли в нем утверждение 1?
1 Работа в предположении, что __STDC_UTF_32__
определен.
Ответы
Ответ 1
Для того чтобы гарантировать, что утверждение должно быть истинным, необходимо, чтобы многобайтовая кодировка, используемая c32rtomb()
, была такой же, как кодировка, используемая для строковых литералов, по крайней мере, до символов, фактически используемых в строке.
C99 7.11.1.1/2 указывает, что setlocale()
с категорией LC_CTYPE
влияет на поведение функций обработки символов и многобайтовых и широких функций символов. Я не вижу никакого явного подтверждения того, что эффект заключается в том, чтобы использовать многобайтовые и широкие кодировки символов, однако это намерение.
Таким образом, многобайтовая кодировка, используемая c32rtomb()
, представляет собой многобайтовое кодирование из локали "C" по умолчанию.
С++ 11 2.14.3/2 указывает, что для соответствующих символов и строковых литералов используются кодирование исполнения, широкое исполнение, UTF-16 и UTF-32. Поэтому std::string narrow
использует исполняющую кодировку для представления этой строки.
Итак, кодировка локали "C" этой строки такая же, как и исполняющая кодировка этой строки?
C99 7.11.1.1/3 указывает, что локаль "C" обеспечивает "минимальную среду" для перевода C. Такая среда будет включать в себя не только наборы символов, но и специальные коды символов. Поэтому я считаю, что это означает не только то, что язык "C" должен поддерживать символы, необходимые для перевода (т.е. Базовый набор символов), но дополнительно, чтобы эти символы в локали "C" должны использовать одни и те же коды символов.
Все символы в строковых литералах являются членами базового набора символов, поэтому преобразование представления char32_t
в представление локали char
"C" должно приводить к той же последовательности значений, что и для компилятора для char
строковый литерал; утверждение должно быть справедливым.
Я не вижу никаких предположений о том, что все, что находится за базовым набором символов, поддерживается совместимым способом между исполняемым кодированием и локалью "C" , поэтому, если ваш строковый литерал использовал любые символы вне базового набора символов, тогда не будет никакой гарантии, что это утверждение будет выполнено. Даже задавая расширенные символы, которые существуют как в наборе символов выполнения, так и в локали "C" , я не вижу никаких требований, чтобы представления соответствовали друг другу.
Ответ 2
TR, связанный в вопросе, говорит
Не более MB_CUR_MAX
сохраняются байты.
который определен (на C99) как
положительное целочисленное выражение с типом size_t
, которое представляет собой максимальное количество байтов в многобайтовом символе для расширенного набора символов, заданного текущей локалью
Я считаю, что это достаточное доказательство того, что целью TR было создание многобайтовых символов, как определено в текущем установленном языке C: UTF-8 для en_US.utf8
, GB18030 для zh_CN.gb18030
и т.д.
Ответ 3
Как я тестировал, в Linux/MacOSX c32rtomb преобразует строки из UTF-32 в кодировки, специфичные для локали. Вы можете использовать nl_langinfo (CODESET), чтобы получить используемую в настоящее время кодировку.
Однако libc использует по умолчанию "C" по умолчанию, который использует ISO-8859-1 в качестве кодировки. Чтобы изменить кодировку, на которую указывает системная среда, обычно UTF-8, но могут быть другими, используйте setlocale (LC_CTYPE, "").
В Windows VS2015 +, однако, c32rtomb всегда преобразуется в UTF-8. Поскольку vcruntime не поддерживает локальные UTF-8 (поддерживаются только старые ANSI/OEM-локаторы), если он соответствует стандарту, c32rtomb/c16rtomb будет полностью идентичен wcrtomb и вообще не используется.