Почему строковые литералы анализируются для последовательностей триграфа в Gnu gcc / g ++?

Рассмотрим эту безобидную программу на C ++:

#include <iostream>
int main() {
std::cout << "(Is this a trigraph??)" << std::endl;
return 0;
}

Когда я компилирую его, используя g ++ версии 5.4.0, я получаю следующую диагностику:

me@my-laptop:~/code/C++$ g++ -c test_trigraph.cpp
test_trigraph.cpp:4:36: warning: trigraph ??) ignored, use -trigraphs to enable [-Wtrigraphs]
std::cout << "(Is this a trigraph??)" << std::endl;
^

Программа запускается, и ее вывод соответствует ожидаемому:

(Is this a trigraph??)

Почему строковые литералы вообще разбираются на триграфы?

Другие компиляторы тоже делают это?

1

Решение

Триграфы были обработаны в фазе перевода 1 (однако они удалены в C ++ 17). Обработка строк, связанных с литералами, происходит на последующих этапах. Как указано в стандарте C ++ 14 (n4140) [Lex.phases] /1.1:

Приоритет среди синтаксических правил перевода определяется
следующие фазы.

  1. Физические символы исходного файла отображаются, в зависимости от реализации, в основной исходный набор символов
    (введение символов новой строки для индикаторов конца строки), если
    необходимо. Допустимый набор физических символов исходного файла:
    реализации. Последовательности триграфа ([lex.trigraph])
    заменены соответствующими односимвольными внутренними представлениями.

    Любой символ исходного файла, не входящий в базовый набор символов
    ([lex.charset]) заменяется именем универсального символа, которое
    обозначает этот характер. (Реализация может использовать любой внутренний
    кодирование, пока фактический расширенный символ встречается в
    исходный файл, и тот же расширенный символ, выраженный в исходном файле
    файл как универсальное символьное имя (то есть, используя обозначение \ uXXXX),
    обрабатываются аналогично, за исключением случаев, когда эта замена возвращается в
    необработанный строковый литерал.)

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

5

Другие решения

Это поведение унаследовано от компиляторов C и в прежние времена, когда мы использовали последовательные терминалы, в которых использовалось только 7 бит (8-й был битом четности). Чтобы разрешить неанглийские языки со специальными символами (например, акцентированные символы на французском или на испанском), ИСО / МЭК 646 кодовые страницы использовали некоторый код ASCII (7 бит) для их представления. В частности, коды 0x23, 0x24 (#$ в ASCII) 0x40 (@), От 0x5B до 0x5E ([\]^), 0x60 (`) и от 0x7B до 0x7E ({|}~) можно заменить на национальные варианты1.

Поскольку они имеют особое значение в C, их можно заменить в исходном коде на триграфы, используя только инвариантную часть ISO 646.

По соображениям совместимости, это было поддержано до C ++ 14, когда только динозавры все еще помнят о (не очень хороших) днях ISO646 и 7-битных кодовых страниц.


1 Например, используется французский вариант: 0x23 £, 0x40 à 0x5b-0x5d °ç§, 0x60 µ0x7B-0x7E éùè¨

1

По вопросам рекламы [email protected]