В стандарте C ++ правильно ли означает, что код компилируется? - PullRequest
1 голос
/ 16 июня 2020

Стандарты C ++ определяют well-formed programs как

C ++ программу, построенную в соответствии с правилами синтаксиса, диагностируемыми семантическими c правилами и правилом одного определения

Мне интересно, компилируется ли вся правильно сформированная программа или нет (если это не так, какие типы ошибок определяют разницу между правильно сформированной программой и компилируемой проблемой). Например, будет ли программа, содержащая ошибки неоднозначности, считаться правильно сформированной?

Ответы [ 2 ]

5 голосов
/ 16 июня 2020

Правильно сформированная программа может иметь неопределенное поведение.

Это указано в примечании и, следовательно, не является технически авторитетным, но кажется, что это намерение, чтобы прекращение компиляции (или «перевод» как стандартные вызовы it) находится в пределах возможного UB:

[intro.defs]

undefined поведение

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

Допустимое неопределенное поведение варьируется от полного игнорирования ситуации с непредсказуемыми результатами до поведения во время трансляции или выполнения программы задокументированным образом c среды (с выдачей сообщения диагностики c или без него), до завершения перевода или выполнения (с выдачей диагностического сообщения c message).

Многие ошибочные программные конструкции не вызывают неопределенного поведения; они должны быть диагностированы.

Оценка константного выражения никогда не показывает поведение, явно заданное как undefined в [intro] - [cpp] этого документа ([expr.const]). - конечное примечание]

Существуют также практические ограничения для реализации:

[выполняет]

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

Более того, в компиляторах могут быть и есть ошибки. Правильно сформированный просто означает, что компилятор, соответствующий стандарту, должен его скомпилировать (с учетом ограничений, упомянутых выше). Компилятор с ошибками не обязательно соответствует стандарту.

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

Если компилятор не согласен с программистом или другим компилятором , то он может не скомпилировать программу, которая, как полагает другая сторона, правильно сформирована.

2 голосов
/ 16 июня 2020

Мне интересно, компилируются ли все правильно сформированные программы или нет

Конечно, на практике нет.

Типичный пример - когда вы запрашиваете оптимизация на огромном блоке перевода , содержащем длинные функции C ++.

(но теоретически да)

См. конечно n3337 стандарт C ++ 11 или C ++ 17 стандарт.

Это случилось со мной в (старом) G CC MELT проект. Я генерировал код C ++, скомпилированный G CC, в основном используя методы транспилятора (или компиляции исходных текстов ) на Lispy DSL моего изобретения для генерации C ++ код G CC плагинов . См. Также this и that .

На практике, если вы сгенерируете single C ++ функцию из ста тысяч операторов, у компилятора возникнут проблемы в его оптимизации.

Большие сгенерированные функции C ++ возможны в генераторах кода GUI (например, FLUID ) или с некоторыми генераторами парсеров, такими как ANTLR (когда базовая грамматика ввода плохо спроектирована), генераторы интерфейсов, такие как SWIG , или с использованием препроцессоров, таких как GPP или GNU m4 (например, GNU autoconf делает). Расширение C ++ template может также создавать сколь угодно большие функции (например, когда вы объединяете несколько шаблонов C ++ container и ask компилятор G CC для оптимизации по ссылке -time с g++ -flto -O2)

Я провел тест и экспериментально наблюдал в предыдущем десятилетии, что компиляция функции C ++ из операторов n может занять O (n 2 ) время (и IIR C O (n log n) пробел ) с g++ -O3. Обратите внимание, что хороший оптимизирующий компилятор C ++ должен выполнять распределение регистров , l oop развертывание , встроенное расширение , что некоторые ABI s (в том числе в Linux / x86-64 ) передача или возврат small struct -s (или экземпляров небольших class -s) через регистры. Все эти оптимизации требуют компромиссов и наталкиваются на некоторый комбинаторный взрыв стену: на практике оптимизация компилятора - по крайней мере неразрешимая проблема и, вероятно, неразрешимая одна . См. Также связанную теорему Райса и прочтите Dragon Book .

Вы можете адаптировать мою manydl. c программа (генерирующая более или менее случайный C код, скомпилированный как несколько плагинов , затем dlopen с их добавлением Linux) для создания C ++. После этого вы сможете выполнить несколько тестов компилятора G CC, поскольку эта программа manydl способна генерировать сотни тысяч подключаемых модулей, содержащих множество более или менее случайных C функций. См. Статью Дреппера как писать разделяемые библиотеки и помните о libgccjit .

См. Также этот черновик отчета ( объясняя больше о компиляции g++) и проекте RefPerSys (генерация кода C ++). Прочтите блог покойного Жака Питра (1934 - октябрь 2019), чтобы увидеть пример C программы , генерирующей полмиллиона строк своего собственного кода C, чей дизайн объясняется в этой статье и той книге .

Прочтите Преуспевание в многолюдном и меняющемся мире: C ++ 2006-2020

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...