Подтвердить что ты не робот

Какая кодировка конвертирует 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__ определен.

4b9b3361

Ответ 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 и вообще не используется.