Действительно ли маркер порядка байтов является допустимым идентификатором?

C++11 вносит множество дополнений в список кодовых точек Unicode, разрешенных в идентификаторах (§E). Это включает в себя метку порядка байтов, которая входит в диапазон FE47-FFFD.

С помощью браузера символов этот диапазон включает в себя целую кучу случайных вещей, начиная с WHITE SESAME DOT и PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET, в том числе некоторые «маленькие знаки препинания», причудливый арабский язык, здесь появляется спецификация, азиатские символы половинной и полной ширины и наконец, включая REPLACEMENT CHARACTER, который обычно используется для обозначения неработающего рендеринга текста.

Наверняка это какая-то ошибка. Они чувствовали необходимость исключить «кунжутные точки», какими бы они ни были, но знак порядка байтов, также известный как устаревший неразрывный пробел нулевой ширины, является справедливой игрой? Когда есть другой неразрывный пробел нулевой ширины, также известный как объединение слов, который также стал приемлемым идентификатором в C++11?

Кажется, что самая элегантная интерпретация стандарта для определения любой формы Unicode в качестве исходного набора символов состоит в том, чтобы начинать файл после необязательной спецификации. Но пользователь также может законно начать файл, используя спецификацию для идентификатора. Это просто некрасиво.

Я что-то упустил, или это явный дефект?


person Potatoswatter    schedule 22.11.2011    source источник
comment
Только не говорите мне, что вы ненавидите кунжутные точки!   -  person R. Martinho Fernandes    schedule 22.11.2011
comment
Я люблю немного кунжута, и я был бы рад приправить им свои программы. Может быть, поэтому это конкретное исключение… такие овощи, как ☙, тоже запрещены. Это не здорово, говорю я тебе.   -  person Potatoswatter    schedule 22.11.2011
comment
+1 кажется мне изворотливым дизайнерским решением. Игнорируя вопрос о том, удаляется ли идентификатор-символ-BOM с начала файла, я хотел бы увидеть, есть ли какое-либо преднамеренное обоснование для разрешения BOM и REPLACEMENT вообще... они, похоже, не предоставляют ничего полезного, только потенциальные ловушки.   -  person bobince    schedule 25.11.2011


Ответы (3)


Моя попытка интерпретации: стандарт устанавливает правила только для абстрактного фрагмента исходного кода.

Ваш компилятор поставляется с понятием "исходный набор символов", который сообщает ему, как закодирован конкретный исходный код файл. Если это кодировка «UTF-16» (т. е. без спецификатора BE/LE и, следовательно, требуется спецификация), то спецификация не является частью потока кодовых точек, а просто конверта файла.

Только после декодирования файла поток кодовых точек передается компилятору.

person Kerrek SB    schedule 22.11.2011
comment
Да, это то, что я имел в виду, начав файл после необязательной спецификации. В случае UTF-8 можно также использовать спецификацию, но, поскольку UTF-8 в любом случае может использоваться по умолчанию, это в основном необязательно. И пользователь мог ввести его буквально как первое в файле. - person Potatoswatter; 22.11.2011
comment
Однако спецификация может появляться в любом месте документа Unicode, а не только в UTF-16 и UTF-32, и не только в качестве первого символа. - person Dietrich Epp; 22.11.2011
comment
@DietrichEpp: Это не противоречие. Вы, безусловно, можете иметь спецификацию в потоке кодовых точек. Я просто говорю, что если UTF-16 является кодировкой вашего файла, первые два байта файла не являются частью закодированного содержимого. Potato: спецификация UTF-8 envelope представляет собой другую трехбайтовую последовательность. В противном случае U+FEFF — это просто обычная кодовая точка. - person Kerrek SB; 22.11.2011

Во-первых, я хочу сказать, что проблема, которую вы описываете, вряд ли имеет значение. Если вашему компилятору требуется спецификация UTF-8 для обработки файла как использующего кодировку UTF-8, то у вас не может быть файла, в котором отсутствует спецификация UTF-8, но где исходный код начинается с U+FEFF в кодировке UTF-8. . Если вашему компилятору не требуется спецификация UTF-8 для обработки файлов UTF-8, вам не следует помещать спецификации UTF-8 в исходные файлы (по словам Майкла Каплана, "ПРЕКРАТИТЕ ИСПОЛЬЗОВАТЬ БЛОКНОТ WINDOWS").

Но да, если компилятор удаляет спецификации, вы можете получить поведение, отличное от предполагаемого. Если вы хотите (неблагоразумно) начинать исходный файл с U+FEFF, но (благоразумно) отказываетесь помещать спецификации в исходный код, вы можете использовать универсальное символьное имя: .

Теперь о моем ответе.

Извлечение символов физического исходного файла не определяется стандартом C++. Объявление кодировки исходного файла для компилятора, форматы файлов для хранения физических исходных символов и сопоставление физических исходных символов файла с базовым исходным набором символов — все это определяется реализацией. Поддержка обработки U+FEFF в начале исходного файла как намека на кодировку лежит в этой области.

Если компилятор поддерживает необязательную спецификацию UTF-8 и не может отличить файл, в котором указана необязательная спецификация, от файла, в котором ее нет, но исходный код начинается с U+FEFF, то это дефект конструкции компилятора и, в более широком смысле. в идее самой спецификации UTF-8.

Чтобы интерпретировать байты данных как текст, необходимо знать кодировку текста, однозначно определенную авторитетным источником. (Вот статья, которая подчеркивает это.) К сожалению, до того, как этот принцип был понят, данные уже передавались между системами, и людям приходилось иметь дело с данными, которые якобы были текстом, но кодировка которых не обязательно была известна. Поэтому они придумали очень плохое решение: угадать. Набор методов, использующих спецификацию UTF-8, является одним из разработанных методов угадывания.

Спецификация UTF-8 была выбрана в качестве подсказки по кодировке по нескольким причинам. Во-первых, он не влияет на видимый текст и поэтому может быть преднамеренно вставлен в текст без видимого эффекта. Во-вторых, файлы, отличные от UTF-8, вряд ли будут содержать байты, которые будут ошибочно приняты за спецификацию UTF-8. Однако это не мешает использованию спецификации быть ничем иным, как угадыванием. Нет ничего, что говорило бы о том, что обычный текстовый файл ISO-8859-1 не может начинаться, например, с U+00EF U+00BB U+00BF. Эта последовательность символов, закодированная в ISO-8859-1, использует ту же кодировку, что и U+FEFF, закодированная в UTF-8: 0xEF 0xBB 0xBF. Любое программное обеспечение, которое полагается на обнаружение спецификации UTF-8, будет сбито с толку таким файлом ISO-8859-1. Таким образом, спецификация не может быть авторитетным источником, хотя предположения, основанные на ней, почти всегда работают.

Помимо того факта, что использование спецификации UTF-8 равносильно угадыванию, есть еще одна причина, по которой это ужасная идея. Это заключается в ошибочном предположении, что изменения в тексте, которые не влияют на визуальное отображение этого текста, вообще не имеют никакого эффекта. Это предположение может быть неверным всякий раз, когда текст используется для чего-то другого, кроме визуального отображения, например, когда он используется в тексте, предназначенном для чтения компьютером в качестве исходного кода.

Итак, в заключение: эта проблема со спецификацией UTF-8 не вызвана спецификацией C++; и если вы абсолютно не вынуждены взаимодействовать с безмозглыми программами, которые этого требуют (другими словами, программами, которые могут обрабатывать только подмножество строк Unicode, начинающихся с U+FEFF), не используйте спецификацию UTF-8.

person bames53    schedule 22.11.2011
comment
В UTF-8 нет спецификации, потому что в UTF-8 вообще нет порядка байтов. Это 8-битный; и 8-битные значения не изменяются из-за проблем с порядком байтов. Спецификация предназначена для UTF-16 (и UTF-32) или других не 8-битных кодировок. - person Nicol Bolas; 23.11.2011
comment
Это правда, что UTF-8 не имеет порядка байтов, однако есть вещь, которую люди называют спецификацией UTF-8, которая не имеет ничего общего с определением порядка байтов. Вещь, на которую ссылается это имя, представляет собой кодировку UTF-8 U + FEFF (нулевая ширина без разрыва пробела), добавленную к обычному тексту. Первоначально мой ответ действительно включал одну ссылку на «метку порядка байтов UTF-8», но я удалю ее, чтобы люди не запутались, и что спецификация имеет какое-то отношение к порядку байтов. ;) - person bames53; 23.11.2011
comment
@NicolBolas: Спецификация UTF-8 существует и имеет номер 0xEF, 0xBB, 0xBF. Однако это бесполезно, так как UTF-8 не имеет порядок байтов (из-за того, что его кодовая единица имеет длину всего один байт и все такое). Это просто индикатор того, что это действительно файл UTF-8. - person Kerrek SB; 23.11.2011
comment
@KerrekSB Не очень хороший, как я подробно описал в своем ответе. - person bames53; 23.11.2011
comment
@KerrekSB Где я сказал, что спецификация UTF-8 была U + 00EF U + 00BB U + 00BF? Я имею в виду файл в кодировке ISO-8859-1, начинающийся с этой последовательности символов (т. е. СТРОЧНАЯ ЛАТИНСКАЯ БУКВА I С ДИАЭРЕЗИСОМ, ДВУХУГОЛЬНАЯ КАТЫЧКА, УКАЗЫВАЮЩАЯ ВПРАВО, ПЕРЕВЕРНУТЫЙ ВОПРОСИТЕЛЬ), но никогда не называл эту последовательность символов UTF-8. Спецификация На самом деле я привожу эту последовательность именно для того, чтобы указать, что ее можно спутать со спецификацией UTF-8, но это не так. - person bames53; 23.11.2011
comment
@bames53: А, хорошо, я неправильно понял. Я удалю комментарий. Прости! - person Kerrek SB; 23.11.2011
comment
@KerrekSB не беспокойтесь. Я также уточнил эту часть своего ответа. - person bames53; 23.11.2011
comment
@bames53: Ура. Я полагаю, что спецификация полезна только в том случае, если у вас есть строго ограниченное семейство, состоящее исключительно из кодировок BOMmed UTF. В этом случае вы можете сказать все, что вам нужно знать, из спецификации. Я не могу представить ни одной ситуации, в которой это когда-либо было бы полезно. - person Kerrek SB; 23.11.2011
comment
Я не могу придумать, как исходный файл может законно начинаться с идентификатора — может, для включаемого файла. Да, это крайне неразумно ;) - person MSalters; 23.11.2011
comment
К сожалению, я не могу просто сказать своим пользователям прекратить использовать Блокнот (и исходный текст от других программистов), и последовательность байтов в любом случае законно вставляется другими редакторами. Кроме того, я намеренно не указал UTF-8 или свою собственную реализацию в вопросе… Я спрашиваю о взаимодействии между стандартом C++ и лучшими практиками, рекомендованными комитетом Unicode, будь то UTF-16 или UTF-32 или что-то еще . - person Potatoswatter; 23.11.2011
comment
@Potatoswatter Ну, ответ в том, что вы ничего не упускаете, но дефект связан с концепцией спецификации. Произвольно, будет ли неразрывный пробел нулевой ширины считаться допустимым символом в идентификаторе, пробелом или чем-то еще. (Хотя я отмечаю, что в стандарте Unicode специально упоминается разрешение Zero Width Joiner в идентификаторах в некоторых случаях). Но независимо от того, что указал С++, у вас все равно будет проблема, которую рекомендует Unicode: если поток Unicode начинается с определенного значения, то это значение не следует рассматривать как часть данных. - person bames53; 23.11.2011
comment
@Potatoswatter Обратите внимание, что комитет по Unicode рекомендует здесь лучшие практики для использования текста. Их рекомендуемые методы выдачи текста не включают спецификацию. Вместо этого они рекомендуют альтернативные способы определения порядка байтов, и ни при каких обстоятельствах не рекомендуется использовать спецификацию для обнаружения или объявления схемы кодирования. Использование BOM было разработано людьми, которые не хотели или не могли использовать передовые методы кодирования текста и Unicode. - person bames53; 23.11.2011
comment
@KerrekSB На самом деле это еще менее полезно. Сравните кодировку BOM с прямым порядком байтов UTF-32 и спецификацию с прямым порядком байтов UTF-16, за которой следует U+0000: 0xFF 0xFE 0x00 0x00. - person bames53; 23.11.2011
comment
@bames53: Ах, да, это ужасно глупо. Почему они не могли хотя бы придумать какую-нибудь 4-байтовую последовательность, которая не является допустимой UTF-16! - person Kerrek SB; 23.11.2011

Эта часть спецификации C++ (и ваш вопрос) связана со спецификацией Unicode. Подумайте, в любом обычном файле юникода внутри файла могут появиться FFFE (или что-то еще), так как мы должны их интерпретировать?

Согласно стандарту Unicode, символ BOM в начале потока/файла не считается символом и игнорируется при представлении.

Когда они говорят, что «файлы C++ могут быть в формате unicode», они также ограничивают всю спецификацию C++ спецификацией unicode. Здесь закон юникода также контролирует спецификацию C++.

Поскольку стандарт Unicode уже определил это поведение (сначала пропустив спецификацию), у авторов стандарта C++ была веская причина не включать это в свои документы. Любой, кто реализует компилятор Unicode C++, также примет во внимание стандарт Unicode.

person Hossein    schedule 22.11.2011
comment
Стандарт C++ не говорит, что файлы C++ могут быть в формате unicode. Способ хранения физических исходных символов выходит за рамки стандарта C++. - person bames53; 23.11.2011
comment
Исходный код C++ не используется для представления (в данном контексте). Хотя наличие невидимых идентификаторов, безусловно, сбивает с толку, спецификация является лишь одним из нескольких таких объектов. Стандарт C++ называет эти кодовые точки возможными идентификаторами, поэтому их нельзя игнорировать. Отсюда мой вопрос. Кроме того, официально рекомендуется не использовать спецификацию UTF-8, хотя они признают, что это один способ определения формата UTF-8. Это затрудняет требование от пользователей идти тем или иным путем. - person Potatoswatter; 23.11.2011