У меня возникли проблемы со зрением, как транзитивность применяется здесь, но я могу говорить на вашем примере.
ли компилятор нужен дополнительный load
инструкции для последнего доступа tmp
(возвращенное значение), потому что он не может сделать вывод, что *i
и *tmp
не псевдоним?
компилятор действительно не может с уверенностью заключить, что *i
и *tmp
не псевдоним в исходном коде, как вы наглядно продемонстрировал.Из этого не следует, что компилятору необходимо исправить команду load
, подразумеваемую абстрактной машинной семантикой оператора *
, но необходимо позаботиться о том, чтобы решить проблему с псевдонимом как-то.
Если да, то [ограничить-квалификационный параметр i
] исправить эту нагрузку?
Добавление restrict
-qualification к параметру i
в определении функции помещает следующее дополнительное требование о поведении программы (полученной из текста C2011, 6.7.3.1/4): во время каждого выполнения bar()
, потому i
является (тривиальным) на основеi
и *i
используются для доступа к объекту оно обозначает, и что обозначенный объект изменяется во время выполнения bar()
(через *i
по крайней мере), все остальное именующее выражение используется для доступа к объекту, назначенному *i
также имеет свой адрес, основанный на i
.
*tmp
имеет доступ, и его адрес, tmp
, не основан на i
. Следовательно, если i == tmp
(то есть, если при некотором вызове i == c->i
), то программа не соответствует. В этом случае его поведение не определено. Компилятор волен испускают код, который принимает на себя программа соответствует установленным требованиям, так, в частности, в restrict
-qualified случае он может испускать код, который предполагает как то, что заявление
*i = 4;
не изменяет *tmp
, и что заявление
*tmp = 5;
не изменяет *i
. Действительно, похоже на определение и выразить намерение restrict
, что компиляторы могут свободно делать именно эти предположения.
В частности, если компилятор выбирает для обработки возможности наложения спектров в исходном коде, выполняя, возможно, избыточную нагрузку *tmp
, то в restrict
-qualified версии может выбрать оптимизацию, исключив, что load
. Однако полученный машинный код ни в коем случае не является , а должен различаться между двумя случаями. То есть вы не можете, в общем, полагаться на компилятор, чтобы использовать все доступные ему оптимизации.
Update:
Вопросы Followup спросить, почему clang
не выполняет определенную оптимизацию при определенных обстоятельствах. Прежде всего, важно повторить, что компиляторы C не несут никакой ответственности за выполнение какой-либо конкретной оптимизации, которая может быть возможна для данного исходного кода, за исключением того, что они сами документируют. Поэтому, как правило, нельзя делать никаких выводов из того факта, что данная оптимизация не выполняется, и редко бывает полезно спросить, почему данная оптимизация не была выполнена.
О том, насколько вы можете пойти - и я интерпретирую вопросы в этом свете - это спросить, является ли рассматриваемая оптимизация тем, что соответствующий компилятор мог иметь. В этом случае стандарт подчеркивает, что, принимая на необычный шаг разъяснения, что restrict
не налагает никаких обязательств оптимизации по реализации:
Переводчика может свободно игнорировать любые или все последствия наложения спектров от использования restrict
.
(C2011, 6.7.3.1/6)
С учетом сказанного, на вопросы.
В этом коде варианте *tmp
является именующим, адрес которого основан на restrict
-qualified указателя c
. Объект, который он обозначает, получает доступ через это значение в пределах области действия функции, а также изменен в пределах этой области (через *tmp
, поэтому компилятор, безусловно, может ее увидеть). Адрес *i
не основан на c
, поэтому компилятор может предположить, что *i
не является псевдонимом *tmp
, так же, как в исходном вопросе.
Этот случай отличается. Хотя разрешено ограничивать-квалифицировать элементы структуры, restrict
имеет эффект только тогда, когда он квалифицирует обычный идентификатор (C2011, 6.7.3.1/1), имена структурных членов которого не являются (C2011, 6.2.3). В этом случае restrict
не имеет никакого эффекта, и для обеспечения соответствующего поведения компилятор должен учитывать возможность того, что c->i
и *i
(и *tmp
) являются псевдонимами.
'вернуть * TMP;' Функция должна возвращать пустое (: = не возвращает значение) – joop
вы имели в виду, чтобы иметь 'container_s * ограничить c', так как вы спрашиваете, является ли оно транзитивно, но ваш первоначальный у кода нет 'ограничений' где-нибудь? – Arkku
Как компиляторы будут * в общем * превращать ваш код C в машинный код, не является предметом ответственности. 'ограничивать' говорит (не) сглаживание с помощью указателей, а способ, если таковой имеется, в котором компилятор обрабатывает обращения с помощью указателя с ограничениями, отличного от доступа через неквалифицированный указатель, является аспектом реализации этого компилятора , –