Ответ 1
Он выглядит как отчет о дефекте 1400: равенство указателя функции относится к этой проблеме и мне кажется, что это нормально для этой оптимизации, но, как показывают комментарии, есть разногласия. В нем говорится (внимание мое):
В соответствии с пунктом 5.10 [expr.eq], только два указателя функций сравните их, если они указывают на ту же функцию. Однако, поскольку оптимизация, реализации в настоящее время выполняют функции псевдонимов, которые имеют идентичные определения. Неясно, нуждается ли Стандарт явно заниматься этой оптимизацией или нет.
и ответ был:
Стандарт четко соответствует требованиям, а - реализациям свободно оптимизировать в рамках ограничений правила "как-если" .
В вопросе возникает вопрос о двух проблемах:
- Хорошо ли, чтобы эти указатели считались равными.
- Можно ли объединить функции
На основе комментариев я вижу две интерпретации ответа:
-
Эта оптимизация в порядке, стандарт дает реализацию этой свободы в соответствии с правилом as-if. Правило as-if рассматривается в разделе
1.9
и означает, что реализация должна только эмулировать наблюдаемое поведение в соответствии с требованиями стандарта.Это еще моя интерпретация ответа. -
Проблема полностью игнорируется, и в заявлении просто говорится, что никакая корректировка стандарта не требуется, потому что, очевидно, правила as-if охватывают это, но интерпретация остается как упражнение для читателя. Хотя я признаю из-за сложности ответа, я не могу отбросить эту точку зрения, и это в конечном итоге является совершенно бесполезным ответом. Это также кажется несовместимым с ответами в других проблемах
NAD
, которые, насколько я могу судить, указывают на проблему, если они существуют.
Что говорится в проекте стандарта
Поскольку мы знаем, что имеем дело с правилом as-if, мы можем начать там и отметить, что в разделе 1.8
говорится:
Если объект не является битовым полем или подобъектом базового класса, равным нулю размер, адрес этого объекта - это адрес первого байта занимает. Два объекта, которые не являются битовыми полями, могут иметь одинаковые адрес, если он является подобъектом другого, или если хотя бы один из них является субобъект базового класса нулевого размера и они имеют разные типы; в противном случае они должны иметь разные адреса. 4
и примечание 4
говорит:
В соответствии с правилом "как есть" реализации разрешено хранить два объекты на одном и том же адресе машины или вообще не хранят объект, если программа не может наблюдать разницу
но в примечании из этого раздела говорится:
Функция не является объектом, независимо от того, занимает она или нет. хранения в том, как объекты выполняются
хотя он не является нормативным, требования к объекту, изложенному в параграфе 1
, не имеют смысла в контексте функции и поэтому согласуются с этой запиской. Таким образом, мы явно ограничены объектами сглаживания с некоторыми исключениями, но такое ограничение не распространяется на функции.
Далее у нас есть раздел 5.10
Операторы равенства, который говорит (внимание мое):
[...] Два указателя сравнивают одинаковые, если они равны нулю, обе указывают на одна и та же функция или оба представляют один и тот же адрес (3.9.2), в противном случае они сравниваются с неравными.
который говорит нам, что два указателя равны, если они:
- Нулевые указатели
- Указывает на ту же функцию
- Представьте тот же адрес
Оба или оба представляют один и тот же адрес, кажется, дают достаточную широту, чтобы позволить компилятору сглаживать две разные функции и не требует указателей на разные функции для сравнения неравных.
Наблюдения
Кит Томпсон сделал несколько замечательных замечаний, которые, как мне кажется, стоит добавить к ответу, так как они попадают в основные проблемы, он говорит:
Если программа печатает результат & foo == & bar, это наблюдаемое поведение; рассматриваемая оптимизация изменяет наблюдаемое поведение.
с которым я согласен, и если бы мы могли показать, что существует требование, чтобы указатели были неравными, что действительно нарушало бы правило as-if, но пока мы не можем это показать.
и
[...] рассмотрите программу, которая определяет пустую функцию и использует их адреса как уникальные значения (подумайте о SIG_DFL, SIG_ERR и SIG_IGNв < signal.h > / <csignal> ). Присвоение им одного и того же адреса разбить такую программу
Как я уже отмечал в своем комментарии, стандарт C требует, чтобы эти макросы генерировали разные значения: от 7.14
в C11:
[...], которые расширяются до постоянных выражений с различными значениями, которые имеют тип, совместимый со вторым аргументом, и возвращаемое значение функции сигнала и значения которых неравны адрес любой декларируемой функции [...]
Итак, хотя этот случай покрыт, возможно, есть и другие случаи, которые сделали бы эту оптимизацию опасной.
Обновить
Ян Хюбичка a gcc
разработчик написал сообщение в блоге Улучшение ссылок и улучшений межпроцессорной оптимизации в GCC 5, сворачивание кода было одной из многих тем, которые он затронул.
Я попросил его прокомментировать, соответствует ли совпадение идентичных функций с одним и тем же адресом или нет, и он говорит, что это не соответствует поведению, и действительно, такая оптимизация нарушит сам gcc
:
Это не соответствует тому, что две функции имеют один и тот же адрес, поэтому MSVC здесь довольно агрессивен. Так, например, разрывает сам GCC, потому что, к моему удивлению, сравнение сравнения выполняется в коде с предварительно скомпилированными заголовками. Он работает для многих других проектов, включая Firefox.
Оглядываясь назад, после нескольких месяцев чтения отчетов о дефектах и размышлений об оптимизации, я склонен к более консервативному прочтению ответов комитета. Принятие адреса функции является наблюдаемым поведением, и поэтому сложение идентичных функций будет нарушать правило as-if.