Является ли С++ 20 'char8_t' таким же, как наш старый 'char'?
В справочнике по CPP документация,
Я заметил для char
Типы символов достаточно велики для представления любого восьмибитного UTF-8 блок кода (начиная с С++ 14)
и для char8_t
тип для представления символов UTF-8, должен быть достаточно большим представлять любую кодовую единицу UTF-8 (8 бит)
Означает ли это, что оба они одного типа? Или у char8_t
есть какая-то другая особенность?
Ответы
Ответ 1
char8_t
отличается от char
. Он ведет себя точно так же, как unsigned char
, хотя в [basic.fundamental]/9
Тип char8_t
обозначает отдельный тип, базовый тип которого - unsigned char
. Типы char16_t
и char32_t
обозначают различные типы, базовыми типами которых являются uint_least16_t
и uint_least32_t
, соответственно, в <cstdint>.
emphasis mine
Обратите внимание, что поскольку стандарт называет его отдельным типом, код, подобный
std::cout << std::is_same_v<unsigned char, char8_t>;
напечатает 0
(false), даже если char8_t
реализован как unsigned char
. Это потому, что это не псевдоним, а отдельный тип.
Следует также отметить, что char
может быть реализован как signed char
или unsigned char
. Это означает, что char
может иметь тот же диапазон и представление, что и char8_t
, но они все еще являются отдельными типами. char
, signed char
, unsigned char
и char8_t
имеют одинаковый размер, но все они разных типов.
Ответ 2
Отказ от ответственности: я являюсь автором предложений char8_t
P0482 и P1423.
В С++ 20 char8_t
отличается от всех других типов. В соответствующем предложении для C, N2231 (который нуждается в обновлении и повторном предложении для WG14), char8_t
будет typedef из unsigned char
, аналогично существующим определениям типов для char16_t
и char32_t
.
В С++ 20 char8_t
имеет базовое представление, которое соответствует unsigned char
. Поэтому он имеет тот же размер (по крайней мере, 8-битный, но может быть больше), выравнивание и целочисленное преобразование ранга, что и unsigned char
, но имеет другие правила наложения имен.
В частности, char8_t
не был добавлен в список типов на [basic.lval] p11. [basic.life] p6.4, [basic.types] p2 или [basic.types] p4. Это означает, что, в отличие от unsigned char
, его нельзя использовать для базового хранилища объектов другого типа, а также для изучения базового представления объектов других типов; другими словами, его нельзя использовать для псевдонимов других типов. Следствием этого является то, что объекты типа char8_t
могут быть доступны через указатели на char
или unsigned char
, но указатели на char8_t
не могут использоваться для доступа к данным char
или unsigned char
. Другими словами:
reinterpret_cast<const char *>(u8"text"); // Ok.
reinterpret_cast<const char8_t*>("text"); // Undefined behavior.
Мотивация для отдельного типа с этими свойствами:
Чтобы обеспечить отдельный тип для символьных данных UTF-8 по сравнению с символьными данными с кодировкой, которая либо зависит от локали, либо требует отдельной спецификации.
Чтобы включить перегрузку для обычных строковых литералов по сравнению со строковыми литералами UTF-8 (поскольку они могут иметь разные кодировки).
Чтобы гарантировать тип без знака для данных UTF-8 (независимо от того, подписан ли char
или нет, определяется реализация).
Чтобы обеспечить лучшую производительность с помощью сглаживания типа; оптимизаторы могут лучше оптимизировать типы, которые не имеют псевдонимов других типов.