Насколько мне известно, когда два указателя (или ссылки) не набирают псевдонимы друг друга, для компилятора допустимо предположить, что они обращаются к разным местоположениям, и выполнить определенные их оптимизации, например, переупорядочить инструкции. Поэтому наличие указателей на разные типы для одинакового значения может быть проблематичным. Однако я думаю, что эта проблема применима только тогда, когда два указателя передаются функциям. Внутри тела функции, где создаются два указателя, компилятор должен быть в состоянии убедиться, что между ними есть связь относительно того, относятся ли они к одному и тому же местоположению. Я прав?
Насколько я знаю, когда два указателя (или ссылки) не набирают псевдоним
друг другу, это допустимо для компилятора сделать предположение
что они адресуют разные места и чтобы убедиться,
их оптимизации, например, переупорядочивание команд.
Правильный. GCC, например, выполняет оптимизацию этой формы, которую можно отключить, передав флаг -fno-strict-aliasing
,
Тем не менее, я думаю, что эта проблема применима только тогда, когда два указателя
перешел к функциям. В теле функции, где два указателя
создаются, компилятор должен быть в состоянии убедиться, что отношения
между ними относительно того, относятся ли они к одному и тому же месту. Я прав?
Стандарт не различает, откуда взялись эти указатели. Если ваша операция имеет неопределенное поведение, программа имеет неопределенное поведение, точка. Компилятор никоим образом не обязан анализировать операнды во время компиляции, но он может дать вам предупреждение.
Реализации, которые спроектированы и предназначены для использования в низкоуровневом программировании, не должны иметь особых трудностей при распознавании общих шаблонов, в которых хранилище одного типа используется повторно или интерпретируется как другое в ситуациях, не связанных с псевдонимами, при условии, что:
В любой конкретной функции или цикле все указатели или l-значения, используемые для доступа к конкретному фрагменту памяти, получены из l-значений общего типа, которые идентифицируют один и тот же объект или элементы одного и того же массива, и
Между созданием указателя производного типа и последним его использованием или любым производным от него указателем все операции с хранилищем выполняются только с использованием производного указателя или других указателей, полученных из него.
Большинство сценариев низкоуровневого программирования, требующих повторного использования или реинтерпретации хранилища, соответствуют этим критериям, и обработка кода, соответствующего этим критериям, обычно будет довольно простой в реализации, предназначенной для низкоуровневого программирования. Если реализация кэширует lvalues в регистрах и выполняет, например, подъем цикла, она может достаточно эффективно поддерживать вышеуказанную семантику, сбрасывая все кэшированные значения типа T всякий раз, когда T или T * используется для формирования указателя или lvalue другого типа. Такой подход может быть оптимальным, но он значительно снизит производительность, чем необходимость полностью блокировать все оптимизации на основе типов.
Обратите внимание, что, вероятно, во многих случаях не стоит даже для реализации, предназначенной для низкоуровневого программирования, пытаться обрабатывать все возможные сценарии, включающие наложение имен. Делать это было бы намного дороже, чем работать с гораздо более распространенными сценариями, которые не включают псевдонимы.
Реализации, которые специализируются для других целей, конечно, не обязаны делать какие-либо попытки поддержать какие-либо исключения из 6.5p7 — даже те, которые часто рассматриваются как часть Стандарта. То, должна ли такая реализация поддерживать такие конструкции, будет зависеть от конкретных целей, для которых она предназначена.