С++ 20 'char8_t' такой же, как наш старый 'char'?

В документации справочника CPP,

Я заметил для char

Типы символов достаточно велики, чтобы представлять любую восьмибитную кодовую единицу UTF-8 (начиная с C++14).

и для char8_t

тип для представления символов UTF-8, должен быть достаточно большим для представления любой кодовой единицы UTF-8 (8 бит)

Означает ли это, что оба они одного типа? Или у char8_t есть еще какие-то особенности?


person Pavan Chandaka    schedule 07.08.2019    source источник
comment
Что ж, из виду становится ясно, что char8_t — это 8-битный тип. Кроме того, знаковость char зависит от компилятора и целевой платформы: значения по умолчанию для ARM и PowerPC обычно не имеют знака, значения по умолчанию для x86 и x64 обычно имеют знак. в то время как char8_t всегда< /b> без знака.   -  person Elliott Frisch    schedule 08.08.2019
comment
или у char8_t есть дополнительное преимущество? - Что ты имеешь в виду?   -  person    schedule 08.08.2019
comment
Я имею в виду любые другие преимущества   -  person Pavan Chandaka    schedule 08.08.2019
comment
Крысы. Я надеялся, что ты имеешь в виду волшебный меч из «Меча и колдуна».   -  person user4581301    schedule 08.08.2019
comment
Логически код может предположить, что строка char8_t всегда содержит текст UTF-8 (за исключением ошибок), тогда как менее безопасно предполагать какую-либо конкретную кодировку строки char без дополнительных знаний об окружающей среде.   -  person Miral    schedule 08.08.2019
comment
Ну, есть есть преимущества. Тип char, как и большая часть наследия С++, всегда был раздражающе нарушен. Вы не знаете, подписано оно или нет, и, строго говоря, вы даже не знаете, сколько в нем битов (хотя 8 — довольно безопасная ставка, никакой гарантии нет). Тип char8_t дает обе гарантии. К сожалению, никто не осмелился просто исправить поврежденный исходный тип (который, по общему признанию, мог сломать существующий код, но что с того... современный C++ в любом случае несовместим с устаревшим C++). Точно так же, как никто не мог побеспокоиться о том, чтобы сделать size_t или ptrdiff_t правильным типом.   -  person Damon    schedule 08.08.2019
comment
@Damon согласно этого комментария не требуется, чтобы char8_t было ровно восемь бит, поэтому в этом отношении ничего не изменилось…   -  person Holger    schedule 08.08.2019
comment
@Holger: Как ни странно, стандарт C++ действительно не требует, чтобы было ровно 8 бит. Он также не требует, чтобы для каких-либо вещей ‹cstdint› он просто говорил Да, бла-бла, так же, как и в C. Так вот, C тоже не говорит... он говорит Да, бла-бла POSIX. К счастью, POSIX на самом деле говорит:-) Это тип точной ширины в разговоре о POSIX (в отличие от типов _least или _fast, которые, по крайней мере, такие же большие, и может быть, ну, в принципе, что угодно).   -  person Damon    schedule 08.08.2019
comment
@Damon C всегда гарантировал, что char имеет не менее 8 бит. POSIX и большинство других систем, таких как Windows, гарантируют, что char равно 8 битам. Но C не говорит Да, бла-бла POSIX. POSIX включает стандарт C, а не наоборот. И если C внезапно не решит отчуждать огромную часть своей ниши, они не собираются делать обязательным именно восьмибитный тип, потому что C является основным языком, используемым для программирования всего современного встраиваемого/нишевого оборудования, которое имеет байты больше восьми. биты.   -  person mtraceur    schedule 23.04.2020


Ответы (2)


char8_t не то же самое, что char. Он ведет себя точно так же, как unsigned char, хотя согласно [basic.fundamental]/9

Тип char8_­t обозначает отдельный тип, базовым типом которого является unsigned char. Типы char16_­t и char32_­t обозначают различные типы, базовыми типами которых являются uint_­least16_­t и uint_­least32_­t соответственно в <cstdint>..

выделено мной


Обратите внимание, что, поскольку стандарт называет его различным типом, такой код, как

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 имеют одинаковый размер, но все они разных типов.

person NathanOliver    schedule 07.08.2019
comment
@MichaelDorgan Но 98 больше, чем 17, а 98 было ... не так весело работать;) - person NathanOliver; 08.08.2019
comment
Возможно, вы захотите упомянуть, что char, в отличие от char8_t, может быть как подписанным, так и беззнаковым. char и char8_t могут иметь один и тот же диапазон и представление (оба имеют один и тот же базовый тип, unsigned char), но они по-прежнему являются разными типами. - person Keith Thompson; 08.08.2019
comment
@НатанОливер Лучше. - person Barry; 08.08.2019
comment
@MichaelDorgan: Разве совместимость с C не увеличивает сложность? как знак вопроса char. - person Jarod42; 08.08.2019
comment
@KeithThompson Я добавил об этом абзац. - person NathanOliver; 08.08.2019
comment
@MichaelDorgan, если вы не знаете, в C также есть char16_t, char32_t и связанные с ними символьные / строковые литералы и функции манипулирования. (А также char, unsigned char, signed char, int8_t и uint8_t конечно) - person M.M; 08.08.2019
comment
По некоторым определениям точно так же. Ключевой особенностью char8_t является то, что он не использует псевдоним всего на свете. - person T.C.; 08.08.2019
comment
Итак, действительно ли нам нужно другое имя для чего-то, что уже существует? - person Michael Chourdakis; 08.08.2019
comment
Что происходит, когда мы превышаем size_t количество целочисленных типов? - person Paul Sanders; 08.08.2019
comment
@MichaelChourdakis Я считаю, что это было сделано ради последовательности. Намного проще написать макрос для получения charN_t, когда 8 является допустимым N. - person NathanOliver; 08.08.2019
comment
using utf8 = char8_t; Помимо имен, char8_t — это не символ, это единица кодирования UTF-8. Наверное придирка. Я просто рад видеть, что C++ становится более подкованным в Unicode, не прибегая к сторонним утилитам (даже отличным, таким как ICU). - person Eljay; 08.08.2019
comment
@M.M - Да, в курсе. Я как бы должен быть моей работой, чтобы убедиться, что все эти вещи продолжают работать. Но когда я нахожусь в системе / ОС и мне снова и снова приходится иметь дело с пограничными случаями C ++ ... В любом случае, так что да, и убирайся с моей лужайки :) - person Michael Dorgan; 08.08.2019
comment
@MichaelChourdakis: Итак, нам действительно нужно другое имя из того, что уже существует? Да. Если я дам вам const char*, это кодировка UTF-8? Вы не знаете. Если вместо этого я дам вам const char8_t *, то, если он не закодирован в UTF-8, я лжец. Типы имеют значение, и если C++ собирается получить достойную поддержку Unicode, у нас должны быть типы, которые представляют строки, закодированные в кодировке Unicode, а не просто так, как хочет компилятор. Единственная реальная проблема с char8_t заключается в том, что несколько существующих API, которые могут принять их, делают это. И эта проблема будет решена, когда Unicode будет готов. - person Nicol Bolas; 08.08.2019
comment
Интересно, что нет требования, чтобы char8_t было ровно 8 бит. Поскольку он имеет то же представление, что и unsigned char, это CHAR_BIT бита. В отличие от uint8_t, который не определен, если нет 8-битного целочисленного типа, char8_t всегда определен. (Вероятно, нет размещенных реализаций с CHAR_BIT != 8.) - person Keith Thompson; 08.08.2019
comment
@KeithThompson, что заставляет меня задаться вопросом, как приложение будет обрабатывать реальный текст в кодировке UTF-8, который определенно представляет собой последовательность 8 бит-байтов, когда нет 8-битного целочисленного типа. Нет необходимости обрабатывать один блок UTF-8, за исключением случаев, когда вы реализуете тот самый код, который соберет их в кодовую точку Unicode, что должно быть реализовано только один раз (предпочтительно в стандартной библиотеке). Этот метод должен иметь возможность определять ввод как массив из 8-битных единиц, которым всегда является текст в кодировке UTF-8. При чтении элемента достаточно любого целочисленного типа не менее 8 бит. - person Holger; 08.08.2019
comment
@Holger: CHAR_BITS равно по крайней мере 8. Предположим, мы имеем дело с реализацией, в которой CHAR_BITS равно (например) 9, и наш текст в кодировке UTF-8 поступает по сети. Вызов read (или любого другого сетевого примитива) будет получать октеты из сети и сохранять их в 9-битных байтах (используя слово в его стандартном значении C++) в памяти. Точно так же файл, содержащий UTF-8, будет хранить каждый субблок UTF-8 в 9-битном байте (с начальным нулевым битом). Файл не будет упаковывать девять единиц UTF-8 в восемь 9-битных байтов. (Или, по крайней мере, не будет, если только кто-то не глупит). - person Martin Bonner supports Monica; 08.08.2019
comment
@MartinBonner, а этот автоматизм работает и в другую сторону, т.е. всегда отбрасывается девятый бит при записи последовательности этих 9-битных байтов в файл или отправке данных по сети? Что ж, это я бы назвал глупостью. Но давайте не будем судить об этой гипотетической архитектуре, давайте поговорим о стандарте C++, который уделяет столько внимания прозрачной поддержке таких гипотетических систем. Как вы думаете, сколько реальных приложений корректно обрабатывают эти аспекты стандарта, чтобы эти приложения могли без проблем работать на таких системах? - person Holger; 08.08.2019
comment
@Holger Как говорит Мартин, входящие данные UTF-8, вероятно, должны храниться в байтах, а не в октетах. Что касается записи вывода, я предполагаю, что запись данных в текстовый поток разделит его на 8 бит, но запись в двоичный поток сохранит все CHAR_BIT бит (потому что вы должны иметь возможность считывать те же двоичные данные, которые вы написали) . Но вряд ли это имеет значение, потому что, насколько я знаю, все размещенные реализации имеют CHAR_BIT==8. (Некоторые DSP устанавливают CHAR_BIT на 16 или 32, но они не размещаются на хосте, поэтому им не нужно поддерживать стандартный ввод-вывод.) - person Keith Thompson; 08.08.2019
comment
@KeithThompson, но означает ли это, что приложения должны читать ввод UTF-8 со специальными функциями или представляют собой байты без знака и «единицы UTF-8», то есть char8_t, просто взаимозаменяемые, даже в этих экзотических системах? У меня также есть ощущение, что это почти никогда не имеет значения, однако должна быть причина, по которой комитет по стандартизации C++ возлагает такое бремя на программиста… - person Holger; 08.08.2019
comment
@Holger: char8_t по определению имеет тот же размер, диапазон и представление, что и unsigned char, независимо от размера. Вероятно, был бы какой-то способ перевести 8-битный текст UTF-8 в форму, которую можно было бы хранить в такой системе. На практике вряд ли встретится. Я не уверен, какое бремя вы имеете в виду. - person Keith Thompson; 09.08.2019
comment
@Holger Это не гипотетическая архитектура - 9-битные байты существовали в прошлом в реальном оборудовании, и C работал на нем, и он делал именно это - верхний бит просто игнорируется при чтении или записи данных сети или хранилища на основе октетов. По сей день подобные системы существуют, хотя новые просто эмулируют 9-битное оборудование поверх 8-битного. (Я называю 9-битный байт банковским байтом, потому что, конечно, единственные люди, желающие сохранить 9-битный байт, — это финансовая индустрия, где они сделают все, чтобы не переписывать программное обеспечение.) - person mtraceur; 23.04.2020
comment
@mtraceur это противоречит. Когда реализация C просто игнорирует 9-й бит, поведение такое же, как если бы стандарт сказал «байт имеет 8 бит», но стандарт этого не говорит. Это позволяет реализациям C, которые не игнорируют этот бит и требуют, чтобы программист приложения имел с ним дело. - person Holger; 23.04.2020
comment
@Holger Я сказал, что это игнорируется специально при выполнении ввода-вывода через носители байтов октетов, причем игнорируется, очевидно, означает, что при чтении устанавливается значение ноль, а при записи не используется, как вы уже обсуждали в предыдущих комментариях. Бит полностью доступен и может использоваться в остальное время. Вся реализация C не игнорирует это, только некоторые подпрограммы ввода-вывода в предоставленных библиотеках. - person mtraceur; 23.04.2020

Отказ от ответственности: я являюсь автором char8_t P0482 и P1423 предложений.

В C++20 тип char8_t отличается от всех остальных типов. В соответствующем предложении для C, N2653, char8_t — это typedef для unsigned char, аналогичный существующим typedef для char16_t и char32_t.

В C++20 char8_t имеет базовое представление, соответствующее unsigned char. Поэтому он имеет тот же размер (минимум 8-битный, но может быть больше), выравнивание и целочисленный ранг преобразования, что и unsigned char, но имеет другие правила псевдонимов.

В частности, char8_t не был добавлен в список типов в [basic.lval] стр.11. [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.

Мотивация для отдельного типа с этими свойствами:

  1. Чтобы предоставить отдельный тип для символьных данных UTF-8 и символьных данных с кодировкой, которая либо зависит от языкового стандарта, либо требует отдельной спецификации.

  2. Чтобы включить перегрузку для обычных строковых литералов и строковых литералов UTF-8 (поскольку они могут иметь разные кодировки).

  3. Для обеспечения беззнакового типа для данных UTF-8 (независимо от того, является ли char подписанным или беззнаковым, определяется реализацией).

  4. Чтобы обеспечить лучшую производительность с помощью типа без псевдонимов; оптимизаторы могут лучше оптимизировать типы, которые не являются псевдонимами других типов.

person Tom Honermann    schedule 11.08.2019
comment
Почему char8_t не uchar8_t? - person Mala; 13.08.2019
comment
Потому что char8_t соответствует char16_t и char32_t (также беззнаковым типам). - person Tom Honermann; 14.08.2019