Подпись char и Unicode в C++0x

Из рабочего проекта C++0x новые типы char (char16_t и char32_t) для обработки Unicode будут беззнаковыми (uint_least16_t и >uint_least32_t будут базовыми типами).

Но насколько я вижу (возможно, не очень далеко), тип char8_t (на основе uint_least8_t) не определен. Почему ?

И это еще больше сбивает с толку, когда вы видите, что новый префикс кодировки u8 введен для строкового литерала UTF-8... на основе старого знакомого (sign/unsigned) char. Почему ?

Обновление: есть предложение добавить новый тип: char8_t

char8_t: тип символов и строк UTF-8 (версия 1) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r1.html


person anno    schedule 06.03.2010    source источник


Ответы (3)


char будет типом, используемым для UTF-8, потому что он переопределен, чтобы быть уверенным, что его можно использовать с ним:

В целях улучшения поддержки Unicode в компиляторах C++ определение типа char было изменено, чтобы иметь как минимум размер, необходимый для хранения восьмибитного кодирования UTF-8, и достаточно большой, чтобы содержать любой элемент базового набора символов исполнения компилятора. Ранее он определялся только как последний. C++0x поддерживает три кодировки Unicode: UTF-8, UTF-16 и UTF-32. В дополнение к ранее отмеченным изменениям в определении char C++0x добавит два новых типа символов: char16_t и char32_t. Они предназначены для хранения UTF-16 и UTF-32 соответственно.

Источник: http://en.wikipedia.org/wiki/C%2B%2B0x< /а>

Большинство приложений UTF-8 уже используют char на ПК/mac.

person Klaim    schedule 06.03.2010
comment
Ни слова о подписи. - person anno; 06.03.2010
comment
Почему неуклюжая формулировка жирным шрифтом? Разве восьмибитное кодирование UTF-8 не является избыточным? - person dan04; 17.03.2010
comment
Ну, это википедия, формулировки часто меняются и могут сильно различаться по качеству. Однако я не нашел другого источника, который обобщает эти функции, связанные с юникодом. - person Klaim; 18.03.2010

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

UTF-8 не представляет кодовые точки напрямую, поэтому не имеет значения, является ли базовый тип u8 подписанным или нет.

person Chris Jester-Young    schedule 06.03.2010
comment
Если я хочу сохранить символ é (U+00E9), то есть двухбайтовую последовательность 0xC3 0xA9, с массивом подписанных символов, это не удастся: signed char e_acute = {0xC3,0xA9} => это урежет значение. Поэтому, если ваша система определяет char как подписанный char, это все еще проблема. Я ошибся ? - person anno; 06.03.2010
comment
Очень редко вам нужно вводить байты вручную: часто, как вы говорите, используется u8. Таким образом, в этом случае старшие байты просто обрабатываются как отрицательные числа. - person Chris Jester-Young; 06.03.2010
comment
Крис, есть ли гарантия, что пара конверсий unsigned char -> signed char -> unsigned char даст исходное значение? Прежнее преобразование определяется реализацией, и я не смог найти ни одного пункта, который гарантировал бы передачу туда и обратно. - person avakar; 06.03.2010
comment
@avakar: я не уверен, почему в этом случае важна передача туда и обратно (если только я неправильно не понял ваш комментарий). Я так понимаю задачу: нужен способ конвертировать кучу char в кучу char16_t или char32_t. Вы можете легко расширить char во время этого преобразования. - person Chris Jester-Young; 06.03.2010
comment
Я хочу сказать, что если вы откуда-то получаете данные UTF-8 (как последовательность чисел в диапазоне 0–255, как определяется UTF-8), вы не можете надежно хранить их в массиве символов, потому что значение, которое вы получите, возвращаясь к unsigned char, может быть другим (и я даже не уверен, что CHAR_BIT гарантированно будет не менее 8). Для надежности вы должны использовать uint_least8_t, и мне кажется полезным и последовательным предоставить для него char8_t typedef. - person avakar; 06.03.2010
comment
Нет, вы никогда не интерпретируете UTF8 напрямую. Вы передаете его функции поддержки времени выполнения, которая преобразует его в родной символьный тип, например wchar_t. Так что не имеет значения, в какой пакет байтов вы его поместите. - person Hans Passant; 06.03.2010
comment
Чтение файла UTF-8 в буфер со знаком char вызовет ту же проблему. Кроме того, если ваш char подписан, вы не можете предположить, что std::string (basic_string‹char›) является допустимой строкой UTF-8. Я не вижу, как это меняется даже с u8? - person anno; 06.03.2010
comment
@avakar: Обычно вы читаете байтовые данные из файла или сети. Обычно они уже хранятся как char, независимо от того, какая подпись является родной для системы. Таким образом, в случае со знаком (в примере OP) 0xC3, 0xA9 читается как -0x3D, -0x57 (в системах с дополнением до двух). Это нормально: функции преобразования все еще могут осмысленно преобразовывать это в int и таким образом обрабатывать их в фактические кодовые точки. - person Chris Jester-Young; 06.03.2010
comment
Гарантированный диапазон char может быть небольшим, как [-127..+127], если он подписан и если реализация использует представление величины со знаком вместо дополнения до двух. На самом деле допустимый диапазон char может быть всего лишь [0..127], если ваш набор символов хоста представляет собой просто ASCII, хотя я думаю, что он все равно должен быть не менее 8 бит. Таким образом, чтение необработанных байтов в массив char кажется теоретически непереносимым. Я всегда использовал массивы unsigned char, когда мне нужен был пакет байтов. Я что-то неправильно понял? - person Adrian McCarthy; 08.03.2012
comment
Не берите в голову. Я читал, что C++0x изменил определение char таким образом, чтобы исключить представления, которые приводят к диапазонам [0..127] и [-127..+127]. . Итак, когда вы используете новый совместимый компилятор, массива char достаточно для хранения пакета байтов. Однако до тех пор unsigned char будет более безопасной ставкой. - person Adrian McCarthy; 08.03.2012

Черновик С++ 0x, похоже, не указывает, являются ли новые типы символов Unicode знаковыми или беззнаковыми. Однако, как уже упоминалось другими, поскольку нет отрицательных кодовых точек Unicode, было бы более разумно, чтобы char16_t и char32_t были беззнаковыми. (С другой стороны, char имело бы смысл быть беззнаковым, но мы имеем дело с «отрицательными» символами с 70-х годов.)

Кроме того, поскольку UTF-16 находится в диапазоне от 0x0 до 0xFFFF (игнорируя суррогатные пары), вам потребуется весь диапазон 16-битного целого числа без знака для правильного представления всех значений. Было бы, по меньшей мере, неудобно, если бы кодовые точки от 0x8000 до 0xFFFF были представлены как отрицательные числа с char16_t.

В любом случае, пока комитет C++0x не скажет что-то определенное по этому поводу, вы всегда можете просто проверить свою реализацию:

#include <type_traits>
#include <iostream>

int main()
{
    std::cout << std::boolalpha << std::is_signed<char16_t>::value << std::endl;
}

Это выводит false с использованием GCC 4.45 в Linux. Так что, по крайней мере, на одной платформе новые типы Unicode определенно беззнаковые.

person Charles Salvia    schedule 08.03.2011