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

Почему в C11 или С++ 11 нет символьного символа ASCII или UTF-8?

Почему нет символа символа UTF-8 в C11 или С++ 11, хотя существуют строковые литералы UTF-8? Я понимаю, что в общем случае символьный литерал представляет собой один символ ASCII, который идентичен однооктевой кодовой точке UTF-8, но ни C, ни С++ не говорят, что кодировка должна быть ASCII.

В принципе, если я прочитаю стандартное право, нет гарантии, что '0' будет представлять целое число 0x30, но u8"0" должен представлять последовательность char 0x30 0x00.

EDIT:

Я знаю, что не каждая точка кода UTF-8 поместилась бы в char. Такой литерал был бы полезен только для одноклеточных кодовых точек (aka, ASCII), поэтому я предполагаю, что называть его "символом символов ASCII" будет более подходящим, так что вопрос все еще стоит. Я просто решил задать вопрос с помощью UTF-8, потому что есть строковые литералы UTF-8. Единственный способ, который я могу представить, с точки зрения совместимости с ASCII-значениями, - это написать константу для каждого символа, что было бы не так уж плохо, если бы было только 128, но все же...

4b9b3361

Ответ 1

Совершенно допустимо писать непортативный C-код, и это является одной из многих веских причин для этого. Не стесняйтесь предполагать, что ваша система использует ASCII или какой-либо их надмножество и предупреждает пользователей о том, что они не должны пытаться запускать вашу программу в системе EBCDIC.

Если вы чувствуете себя очень щедрым, вы можете закодировать чек. Известно, что программа gperf генерирует код, который включает такую ​​проверку.

_Static_assert('0' == 48, "must be ASCII-compatible");

Или, для компиляторов pre-C11,

extern int must_be_ascii_compatible['0' == 48 ? 1 : -1];

Если вы находитесь на C11, вы можете использовать префикс u или u для символьных констант, но не префикс u8...

/* This is useless, doesn't do what you want... */
_Static_assert(0, "this code is broken everywhere");
if (c == '々') ...

/* This works as long as wchar_t is UTF-16 or UTF-32 or UCS-2... */
/* Note: you shouldn't be using wchar_t, though... */
_Static_assert(__STDC_ISO_10646__, "wchar_t must be some form of Unicode");
if (c == L'々') ...

/* This works as long as char16_t is UTF-16 or UCS-2... */
_Static_assert(__STDC_UTF_16__, "char16_t must be UTF-16");
if (c == u'々') ...

/* This works as long as char32_t is UTF-32... */
_Static_assert(__STDC_UTF_32__, "char32_t must be UTF-32");
if (c == U'々') ...

Существуют некоторые проекты, написанные на очень портативном C и перенесенные в не-ASCII-системы (example). Для этого потребовалось нетривиальное количество усилий по переносу, и нет никаких оснований прилагать усилия, если вы не знаете, что хотите запустить свой код в системах EBCDIC.

О стандартах: Люди, пишущие стандарт C, должны бороться со всеми возможными реализациями C, включая некоторые совершенно странные. Известны системы, в которых sizeof(char) == sizeof(long), CHAR_BIT != 8, интегральные типы имеют ловушечные представления, sizeof(void *) != sizeof(int *), sizeof(void *) != sizeof(void (*)()), va_list выделены в кучу и т.д. Это кошмар.

Не бейте себя, пытаясь написать код, который будет запускаться в системах, о которых вы даже не слышали, и не пытайтесь найти гарантии в стандарте C.

Например, что касается стандарта C, следующая допустимая реализация malloc:

void *malloc(void) { return NULL; }

Обратите внимание, что в то время как константы u8"..." гарантированы как UTF-8, u"..." и u"..." не имеют гарантий, кроме того, что кодировка составляет 16 бит и 32 бита на символ соответственно, а фактическая кодировка должна быть документированы реализацией.

Резюме: Безопасно принимать совместимость ASCII в 2012 году.

Ответ 2

Литеральный символ UTF-8 должен иметь переменную длину - для many большинство из них, невозможно хранить одиночный символ в char или wchar, какой тип он должен иметь, тогда? Поскольку у нас нет типов переменной длины в C, а не на С++, кроме массивов фиксированных типов размеров, единственным разумным типом для него будет const char * - и строки C должны быть завершены с нулевой отметкой, поэтому он не будет ничего не меняйте.

Что касается редактирования:

Цитата из стандарта С++ 11:

Глифы для членов базового набора символов источника предназначены для идентификации символов из подмножества ISO/IEC 10646, который соответствует набору символов ASCII. Однако, поскольку сопоставление от исходных символов файла к исходному набору символов (описано в фазе 1 перевода) задано как определено в реализации, требуется реализация, чтобы документировать, как основные исходные символы представлены в исходных файлах.

(сноска к 2.3.1).

Я думаю, что это хорошая причина не гарантировать это. Хотя, как вы отметили в комментарии здесь, для большинства (или каждого) основного компилятора, ASCII-символьные литералы гарантируют реализацию.

Ответ 3

Для С++ это рассмотрено Эволюционная рабочая группа 119: добавление букв символов u8, в разделе Мотивация говорится:

У нас есть пять префиксов кодирования для строковых литералов (none, L, u8, u, U) но только четыре для символьных литералов - недостающий - u8. Если узкий набор символов выполнения не является ASCII, символами символа u8 обеспечит способ записи символьных литералов с гарантированным ASCII кодирование (кодировка с одним кодом u8 - это точно ASCII). Добавление поддержка этих литералов добавит полезную функцию и сделает язык немного более последователен.

EWG обсудила идею добавления символов символа u8 в Rapperswil и приняла изменение. В этом документе представлена ​​формулировка этого расширение.

Это было включено в рабочий проект, используя формулировку N4267: добавление букв символов u8, и мы можем найти формулировку на этом последнем черновик стандарта N4527 и обратите внимание, как раздел 2.14.3 говорят, что они ограничены кодовыми точками, которые вписываются в единый кодовый блок UTF-8:

Литерал символов, начинающийся с u8, например u8'w ', является символом литерал типа char, известный как литерал символа UTF-8. Значение Литерал символа UTF-8 равен его значению кодовой точки ISO10646, при условии, что значение кодовой точки можно представить с помощью одного UTF-8 (то есть, если он является символом US-ASCII). Литеральный символ UTF-8, содержащий несколько c-символов, плохо сформирован.

Ответ 4

Если вы не верите, что ваш компилятор будет обрабатывать '0' как символ ASCII 0x30, тогда вы можете использовать static_cast<char>(0x30).

Ответ 5

Как вам известно, символы с кодировкой UTF-8 нуждаются в нескольких октетах, поэтому char s, поэтому для них естественным типом является char[], который действительно является типом строкового литерала u8 -prefixed! Таким образом, C11 находится на правильном пути, просто придерживаясь его синтаксических соглашений, используя " для строки, которую нужно использовать в качестве массива char, вместо того, чтобы подразумеваемое семантическое предложение использовать ' вместо.

Примерно "0" по сравнению с u8"0", вы правильно читаете, только последний гарантированно будет идентичен { 0x30, 0 } даже в системах EBCDIC. Кстати, сам факт, что первый не может быть удобно обработан в вашем коде, если вы обратите внимание на предопределенный идентификатор __STDC_MB_MIGHT_NEQ_WC__.