В вычислительной технике псевдонимы описывают ситуацию, в которой к местоположению данных в памяти можно получить доступ через различные символические имена в программе. Таким образом, изменение данных через одно имя неявно изменяет значения, связанные со всеми псевдонимами, чего может не ожидать программист. В результате псевдонимы особенно затрудняют понимание, анализ и оптимизацию программ. Анализаторы псевдонимов намерены создавать и вычислять полезную информацию для понимания псевдонимов в программах.
Псевдонимизация может возникнуть в любом языке, который может ссылаться на одно место в памяти с более чем одним именем (например, с указателями ). Это распространенная проблема с функциями, которые принимают аргументы указателей, и их толерантность (или ее отсутствие) к псевдонимам должна быть тщательно документирована, особенно для функций, которые выполняют сложные манипуляции с переданными им областями памяти.
Контролируемое поведение псевдонимов может быть желательным в некоторых случаях (то есть поведение псевдонимов, которое указано, в отличие от того, которое включено в структуру памяти в C). Это обычная практика в Fortran . Язык программирования Perl определяет в некоторых конструкциях поведение псевдонимов, например, в циклах. Это позволяет изменять определенные структуры данных напрямую с меньшим количеством кода. Например,foreach
мой @массив = ( 1 , 2 , 3 ); foreach my $element ( @array ) { # Увеличиваем $element, тем самым автоматически # изменяя @array, поскольку $element ''присвоен'' # каждому из элементов @array по очереди. $element ++ ; } распечатать "@array \n" ;
в результате выведет "2 3 4". Если бы кто-то хотел обойти эффекты наложения, он мог бы скопировать содержимое индексной переменной в другую и изменить копию.
Оптимизаторам часто приходится делать консервативные предположения о переменных, когда возможно использование псевдонимов. Например, знание значения переменной (например, равно x
5) обычно позволяет выполнять определенные оптимизации (например, распространение констант ). Однако компилятор не может использовать эту информацию после присвоения другой переменной (например, в C, *y = 10
), поскольку может оказаться, что *y
является псевдонимом x
. Это может произойти после присвоения типа y = &x
. В результате этого присвоения значению также изменится *y
значение , поэтому распространение информации, равной 5, на следующие операторы может быть потенциально неверным (если действительно является псевдонимом ). Однако, если есть информация об указателях, процесс распространения констант может сделать запрос типа: может быть псевдонимом ? Тогда, если ответ отрицательный, может быть безопасно распространен.x
x
*y = 10
*y
x
x
*y
x = 5
Другая оптимизация, на которую влияет псевдоним, — это переупорядочивание кода. Если компилятор решает, что x
не псевдоним *y
, то код, который использует или изменяет значение , x
может быть перемещен перед присваиванием *y = 10
, если это улучшит планирование или позволит выполнить больше оптимизаций цикла .
Чтобы обеспечить такую оптимизацию предсказуемым образом, стандарт ISO для языка программирования C (включая его более новую редакцию C99 , см. раздел 6.5, параграф 7) определяет, что недопустимо (за некоторыми исключениями) обращаться к одному и тому же участку памяти с помощью указателей разных типов. Поэтому компилятор может предположить, что такие указатели не имеют псевдонимов. Это правило, известное как правило строгого псевдонимирования , иногда позволяет добиться впечатляющего повышения производительности, [1] но, как известно, нарушает некоторый в остальном допустимый код. Несколько программных проектов намеренно нарушают эту часть стандарта C99. Например, Python 2.x сделал это для реализации подсчета ссылок , [2] и потребовал внесения изменений в базовые структуры объектов в Python 3 для включения этой оптимизации. Ядро Linux делает это, потому что строгое псевдонимирование вызывает проблемы с оптимизацией встроенного кода. [3] В таких случаях при компиляции с помощью gcc эта опция -fno-strict-aliasing
вызывается для предотвращения нежелательных оптимизаций, которые могут привести к получению неожиданного кода.
Термин «алиасинг» также используется для описания ситуации, когда из-за выбора конструкции оборудования или сбоя оборудования один или несколько доступных битов адреса не используются в процессе выбора памяти. [4] Это может быть конструкторским решением, если доступно больше битов адреса, чем необходимо для поддержки установленного устройства(-ий) памяти. В случае сбоя один или несколько битов адреса могут быть закорочены вместе или могут быть принудительно подключены к земле (логический 0) или напряжению питания (логическая 1).
Для этого примера, предположим, что конструкция памяти имеет 8 ячеек, требующих только 3 адресных линии (или бита , поскольку 2 3 = 8). Адресные биты (называемые A2 по A0) декодируются для выбора уникальных ячеек памяти следующим образом, в стандартной манере двоичного счетчика :
В таблице выше каждая из 8 уникальных комбинаций адресных битов выбирает различную ячейку памяти. Однако, если один адресный бит (например, A2) будет замкнут на землю, таблица будет изменена следующим образом:
В этом случае, поскольку A2 всегда равен нулю, первые четыре ячейки памяти дублируются и снова появляются как вторые четыре. Ячейки памяти с 4 по 7 стали недоступными.
Если бы это изменение произошло с другим адресным битом, результаты декодирования были бы другими, но в целом эффект был бы тем же: потеря одного адресного бита сокращает доступное пространство памяти вдвое, что приводит к дублированию (наложению имен) оставшегося пространства.