Копирование данных в локальное хранилище может быть полезным, чтобы компиляторы могли доказать, что никакие другие обращения через другие указатели не читают и не пишут его.
Так что в основном по той же причине, по которой вы использовали бы int *restrict p
.Если вы используете void func(struct foo *restrict ptr)
, то вы обещаете компилятору, что любой доступ к ptr->member
будет , а не , что приведет к изменению значения, прочитанного вами через любой другой указатель или из переменной глобальной области видимости.
Анализ псевдонимов на основе типов уже может существенно помочь;Например, доступ через float*
не может повлиять на объекты int
.(Если ваша программа не содержит UB со строгим псевдонимом; некоторые компиляторы позволяют вам определять это поведение, например, gcc -fno-strict-aliasing
).
Если вы не выполняете присваивания или не читаете другие указатели (которые, по предположению компилятора, могутуказывать на член структуры), это не будет иметь значения: анализ псевдонимов будет успешным и позволит компилятору сохранить член структуры в регистре для других обращений к памяти, как это может быть для локального.
(анализ псевдонимов, как правило, прост для местных жителей, особенно если они никогда не брали свой адрес, тогда ничто не может указывать на них.)
Кстати, причина, по которой компилятору разрешеноОптимизация доступа к памяти без volatile
/ не _Atomic
заключается в том, что записывать неатомарный объект в то время, когда другой поток читает или записывает его, является неопределенным поведением.
Это делает его безопасным дляПредположим, что переменные не изменятся, если вы не напишите их сами, и что вам не нужно, чтобы значение в памяти было "синхронизировано" с Cабстрактная машина, за исключением случаев, когда вы выполняете не встроенные вызовы функций.(Для любого объекта, на который может указывать какая-то неизвестная функция. Обычно это не относится к локальным переменным, таким как счетчики циклов, поэтому они могут храниться в регистрах, сохраняющих вызовы, вместо того, чтобы разливаться / перезагружаться.)
Но есть потенциальная обратная сторона в объявлении локальных объектов для хранения копий глобальных или указываемых данных: если компилятор не сохранит этот локальный объект в регистре для всей функции, он может в конечном итоге фактически скопироватьданные в память стека, чтобы они могли перечитать оттуда.(Если он не может доказать, что исходный объект не изменился.)
Обычно предпочитают удобочитаемость по сравнению с этим уровнем микрооптимизации, но взгляните на оптимизированный asm для некоторой платформытебя волнует, если тебе любопытно.Если происходит много ненужного сохранения / перезагрузки, попробуйте использовать местные.