Из Википедии, бесплатной энциклопедии
  (Перенаправлено из псевдонима указателя )
Перейти к навигации Перейти к поиску

В вычислениях , сглаживание описывает ситуацию , в которой данные о местоположении в памяти могут быть доступны через различные символические имена в программе. Таким образом, изменение данных с помощью одного имени неявно изменяет значения, связанные со всеми псевдонимами, чего программист может не ожидать. В результате псевдонимы особенно затрудняют понимание, анализ и оптимизацию программ. Анализаторы псевдонимов предназначены для получения и вычисления полезной информации для понимания псевдонимов в программах.

Примеры [ править ]

Переполнение буфера [ править ]

Например, в большинстве реализаций языка программирования C не выполняется проверка границ массива . Затем можно использовать реализацию языка программирования компилятором и соглашения на языке ассемблера в компьютерной архитектуре для достижения эффектов сглаживания путем записи вне массива (тип переполнения буфера ). Это вызывает неопределенное поведение в соответствии со спецификацией языка C; однако многие реализации C будут демонстрировать эффекты наложения имен, описанные здесь.

Если в стеке создается массив с переменной, расположенной в памяти непосредственно рядом с этим массивом , можно индексировать за пределами массива и напрямую изменять переменную, изменяя соответствующий элемент массива. Например, если есть intмассив размером 2 (для этого примера, вызывая его arr), рядом с другой intпеременной (назовите ее i) arr[2](т.е. 3-й элемент) будет назначен псевдоним, iесли они находятся рядом в памяти.

# включить <stdio.h>int  main () {  int  arr [ 2 ]  =  {  1 ,  2  };  int  i = 10 ; / * Записываем после окончания обр. Неопределенное поведение в стандарте C, в некоторых реализациях будет записывать в i. * /  arr [ 2 ]  =  20 ; printf ( "элемент 0:% d \ t " ,  arr [ 0 ]);  // выводит 1  printf ( "element 1:% d \ t " ,  arr [ 1 ]);  // выводит 2  printf ( "element 2:% d \ t " ,  arr [ 2 ]);  // выводит 20, если сглаживание произошло  printf ( "i:% d \ t \ t " ,  i );  // может также вывести 20, а не 10, из-за наложения имен, но компилятор может сохранить i в регистре и вывести 10 / * размер arr по-прежнему равен 2. * /  printf ( "arr size:% d \ n " ,  sizeof ( arr )  /  sizeof ( int )); }

Это возможно в некоторых реализациях C, потому что массив является блоком непрерывной памяти, а ссылки на элементы массива просто смещены от адреса начала этого блока, умноженного на размер одного элемента. Поскольку в C нет проверки границ, возможна индексация и адресация за пределами массива. Обратите внимание, что вышеупомянутое поведение псевдонима является неопределенным . Некоторые реализации могут оставлять пространство между массивами и переменными в стеке, например, для выравнивания переменных по ячейкам памяти, которые кратны собственному размеру слова архитектуры . Стандарт C обычно не определяет, как данные должны быть размещены в памяти. (ИСО / МЭК 9899: 1999, раздел 6.2.6.1).

Компилятор не ошибается, если не учитывает эффекты псевдонима для обращений, выходящих за пределы массива.

Псевдонимы указателей [ править ]

Другая разновидность псевдонимов может иметь место на любом языке, который может относиться к одному месту в памяти с более чем одним именем (например, с указателями ). См. Пример C алгоритма замены XOR, который является функцией; он предполагает, что два переданных ему указателя различны, но если они фактически равны (или являются псевдонимами друг друга), функция завершается ошибкой. Это обычная проблема с функциями, которые принимают аргументы-указатели, и их допуск (или отсутствие такового) к алиасингу должен быть тщательно задокументирован, особенно для функций, которые выполняют сложные манипуляции с переданными им областями памяти.

Указанный псевдоним [ править ]

В некоторых случаях может быть желательно контролируемое поведение псевдонимов (то есть, поведение псевдонимов, которое указано, в отличие от того, что разрешено макетом памяти в C). Это обычная практика в Фортране . В некоторых конструкциях язык программирования Perl определяет поведение псевдонимов, например, в циклах. Это позволяет изменять определенные структуры данных напрямую с меньшим количеством кода. Например,foreach

мой  @array  =  ( 1 ,  2 ,  3 );foreach  my  $ element  ( @array )  {  # Увеличивает $ element, тем самым автоматически  # модифицируя @array, так как $ element имеет псевдонимы  # для каждого из элементов @ array по очереди.  $ element ++ ; }напечатать  "@array \ n" ;

в результате распечатает «2 3 4». Если кто-то хочет обойти эффекты сглаживания, можно скопировать содержимое индексной переменной в другую и изменить копию.

Конфликты с оптимизацией [ править ]

Оптимизаторам часто приходится делать консервативные предположения о переменных, когда возможно сглаживание. Например, знание значения переменной (например, x5) обычно позволяет выполнять определенные оптимизации (например, постоянное распространение ). Однако компилятор не может использовать эту информацию после присвоения другой переменной (например, в C *y = 10), потому что это может быть *yпсевдоним x. Это могло произойти после задания вроде y = &x. В результате этого присвоения *yзначение x также будет изменено, поэтому распространение информации, равной x5, на следующие инструкции *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 стали недоступны.

Если бы это изменение произошло с другим адресным битом, результаты декодирования были бы другими, но в целом эффект был бы таким же: потеря одного адресного бита сокращает доступное пространство памяти наполовину, что приводит к дублированию (псевдониму) оставшееся место.

См. Также [ править ]

  • Сглаживание
  • Псевдонимы для использования этого слова в применении к обработке сигналов, включая компьютерную графику

Ссылки [ править ]

  1. Майк Эктон (01.06.2006). «Понимание строгого псевдонима» .
  2. ^ Нил Schemenauer (2003-07-17). «Строгий псевдоним ANSI и Python» .
  3. ^ Линус Торвальдс (2003-02-26). «Re: Неверная компиляция без -fno-strict-aliasing» .
  4. ^ Майкл Барр (27.07.2012). «Программное тестирование памяти» .

Внешние ссылки [ править ]

  • Понимание строгого псевдонима - статья Майка Эктона
  • Псевдонимы, приведение указателей и gcc 3.3 - информационная статья в списке рассылки NetBSD
  • Анализ псевдонимов на основе типов в C ++ - Информационная статья об анализе псевдонимов на основе типов в C ++
  • Understand C / C ++ Strict Aliasing - статья о строгом псевдониме, изначально взятая из вики-страницы разработчика boost