~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ EBDDA8FE192275529C2A3F8511C7E64A__1714527900 ✰
Заголовок документа оригинал.:
✰ Name mangling - Wikipedia ✰
Заголовок документа перевод.:
✰ Искажение имени — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Name_mangling ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/eb/4a/ebdda8fe192275529c2a3f8511c7e64a.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/eb/4a/ebdda8fe192275529c2a3f8511c7e64a__translat.html ✰
Дата и время сохранения документа:
✰ 21.06.2024 12:52:18 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 1 May 2024, at 04:45 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Искажение имени — Википедия Jump to content

Искажение имени

Из Википедии, бесплатной энциклопедии

В компилятора конструкции искажение имен (также называемое украшением имени ) — это метод, используемый для решения различных проблем, вызванных необходимостью разрешения уникальных имен для объектов программирования во многих современных языках программирования .

Он предоставляет средства для кодирования добавленной информации в имя функции , структуры , класса или другого типа данных , чтобы передать больше семантической информации от компилятора к компоновщику .

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

Любой объектный код , созданный компиляторами, обычно связывается с другими частями объектного кода (созданными тем же или другим компилятором) с помощью программы, называемой компоновщиком . Компоновщику требуется большой объем информации о каждом программном объекте. Например, чтобы правильно связать функцию, ей нужно ее имя, количество аргументов и их типы и так далее.

Простые языки программирования 1970-х годов, такие как C , различали подпрограммы только по их имени, игнорируя другую информацию, включая типы параметров и возвращаемых значений. Более поздние языки, такие как C++ , определили более строгие требования к подпрограммам, которые должны считаться «равными», такие как типы параметров, тип возвращаемого значения и соглашение о вызове функции. Эти требования позволяют перегружать методы и обнаруживать некоторые ошибки (например, использование разных определений функции при компиляции разных файлов исходного кода ). Эти более строгие требования необходимы для работы с существующими программирования инструментами и соглашениями . Таким образом, дополнительные требования были закодированы в имени символа, поскольку это была единственная информация, которую традиционный компоновщик имел о символе.

Другое использование искажения имен — обнаружение добавленных изменений, не связанных с сигнатурой, таких как чистота функции или возможность потенциального возникновения исключения или запуска сборки мусора . Примером языка, делающего это, является D . [1] [2] Это скорее упрощенная проверка ошибок. Например, функции int f(); и int g(int) pure; могли быть скомпилированы в один объектный файл, но тогда их подписи менялись на float f(); int g(int);и использовался для компиляции другого источника, вызывающего его. Во время компоновки компоновщик обнаружит отсутствие функции. f(int)и вернуть ошибку. Аналогично, компоновщик не сможет определить, что тип возвращаемого значения fотличается и возвращает ошибку. В противном случае будут использоваться несовместимые соглашения о вызовах, что, скорее всего, приведет к неправильному результату или приведет к сбою программы. Манглирование обычно не фиксирует каждую деталь процесса вызова. Например, он не полностью предотвращает такие ошибки, как изменение элементов данных структуры или класса. Например, struct S {}; void f(S) {} можно скомпилировать в один объектный файл, тогда определение для S изменился, чтобы быть struct S { int x; }; и используется при составлении вызова f(S()). В таких случаях компилятор обычно использует другое соглашение о вызовах, но в обоих случаях f будет преобразовано в одно и то же имя, поэтому компоновщик не обнаружит эту проблему, и результатом обычно будет сбой или повреждение данных или памяти во время выполнения.

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

С [ править ]

Хотя искажение имен обычно не требуется и не используется в языках, которые не поддерживают перегрузку функций , таких как C и классический Pascal , они используют его в некоторых случаях для предоставления дополнительной информации о функции. Например, компиляторы, предназначенные для платформ Microsoft Windows , поддерживают различные соглашения о вызовах , которые определяют способ отправки параметров в подпрограммы и возврата результатов. Поскольку различные соглашения о вызовах несовместимы друг с другом, компиляторы искажают символы кодами, подробно описывающими, какое соглашение следует использовать для вызова конкретной процедуры.

Схема искажения для Windows была разработана Microsoft, и ей неофициально следовали другие компиляторы, включая Digital Mars , Borland и GNU Compiler Collection (GCC), при компиляции кода для платформ Windows. Схема применима даже к другим языкам, таким как Pascal , D , Delphi , Fortran и C# . Это позволяет подпрограммам, написанным на этих языках, вызывать существующие библиотеки Windows , используя соглашение о вызовах, отличное от используемого по умолчанию.

При компиляции следующих примеров C:

int   _cdecl      ж   (  int   x  )   {   возвращение   0  ;    } 
 int   _stdcall    g   (  int   y  )   {   return   0  ;    } 
 int   _fastcall   ч   (  int   z  )   {   return   0  ;    } 

32-битные компиляторы выдают соответственно:

_ф
 _g@4
 @h@4
 

в stdcall и fastcall схем искажения, функция кодируется как _name@X и @name@Xсоответственно, где X — количество байтов в десятичном формате аргумента(ов) в списке параметров (включая переданные в регистрах для быстрого вызова). В случае cdecl, имя функции просто начинается с подчеркивания.

В 64-битном соглашении Windows (Microsoft C) нет ведущего подчеркивания. Эта разница может в некоторых редких случаях привести к неразрешенным внешним проблемам при переносе такого кода на 64-битную версию. Например, код Фортрана может использовать «псевдоним» для связи с методом C по имени следующим образом:

ПОДПРОГРАММА  f  () 
 !DEC$ АТРИБУТЫ C, Псевдоним:'_f' :: f 
 КОНЕЦ ПОДПРОДИНЫ 

Это будет нормально компилироваться и компоноваться под 32-битной версией, но генерировать неразрешенный внешний файл. _fпод 64 бита. Одним из способов решения этой проблемы является вообще не использовать «псевдоним» (в котором имена методов обычно должны быть написаны с заглавной буквы в C и Fortran). Другой способ — использовать опцию BIND:

ПОДПРОГРАММА  f  ()   BIND  (  C  ,  NAME  =  "f"  ) 
 КОНЕЦ ПОДПРОГРАММЫ 

В C большинство компиляторов также искажают статические функции и переменные (а в C++ функции и переменные, объявленные как статические или помещенные в анонимное пространство имен) в единицах перевода, используя те же правила искажения, что и для их нестатических версий. Если функции с одинаковым именем (и параметрами для C++) также определены и используются в разных единицах перевода, это также приведет к тому же имени, что потенциально может привести к конфликту. Однако они не будут эквивалентны, если вызываются в соответствующих единицах перевода. Компиляторы обычно могут произвольно искажать эти функции, поскольку прямой доступ к ним из других единиц трансляции незаконен, поэтому им никогда не потребуется связывание между различными объектными кодами (их связывание никогда не требуется). Чтобы предотвратить конфликты ссылок, компиляторы будут использовать стандартное искажение, но будут использовать так называемые «локальные» символы. При связывании множества таких единиц перевода может быть несколько определений функции с одним и тем же именем, но результирующий код будет вызывать только одно или другое в зависимости от того, из какой единицы перевода он получен. Обычно это делается с помощью механизм перемещения .

С++ [ править ]

Компиляторы C++ являются наиболее распространенными пользователями искажения имен. Первые компиляторы C++ были реализованы как трансляторы исходного кода C , который затем компилировался компилятором C в объектный код; из-за этого имена символов должны были соответствовать правилам идентификаторов C. Даже позже, с появлением компиляторов, которые создавали машинный код или ассемблер напрямую, системный компоновщик обычно не поддерживал символы C++, и искажения по-прежнему требовались.

Язык C++ не определяет стандартную схему оформления, поэтому каждый компилятор использует свою собственную. C++ также имеет сложные возможности языка, такие как классы , шаблоны , пространства имен и перегрузка операторов , которые изменяют значение определенных символов в зависимости от контекста или использования. Метаданные об этих функциях можно устранить, исказив (украсив) имя символа . Поскольку системы изменения имен для таких функций не стандартизированы для разных компиляторов, немногие компоновщики могут связывать объектный код, созданный разными компиляторами.

Простой пример [ править ]

Одна единица трансляции C++ может определять две функции с именами f():

int    f   ()   {   возвращение   1  ;    } 
 Int    F   (  int  )    {   возвращение   0  ;    } 
 void   g   ()   {   int   я   =   f  (),   j   =   f  (  0  );    } 

Это отдельные функции, не имеющие никакой связи друг с другом, кроме названия. Поэтому компилятор C++ закодирует информацию о типе в имени символа, в результате чего получится что-то вроде:

int    __f_v   ()   {   возвращение   1  ;    } 
 Int    __f_i   (  int  )    {   возвращение   0  ;    }  
 void   __g_v   ()   {   int   i   =   __f_v  (),   j   =   __f_i  (  0  );    } 

Несмотря на то, что его имя уникально, g() все еще искажено: искажение имен применяется ко всем символам C++ (за исключением символов в extern "C"{} блокировать).

Сложный пример [ править ]

Искаженные символы в этом примере в комментариях под соответствующим именем идентификатора созданы компиляторами GNU GCC 3.x в соответствии с ABI IA-64 (Itanium):

пространство имен   Википедии  
 { 
    класса   статья  
    { 
    public  : 
       std  ::  string   format   ();     // = _ZN9wikipedia7article6formatEv 

       bool   print_to   (  std  ::  ostream  &  );     // = _ZN9wikipedia7article8print_toERSo 

       class   wikilink  
       { 
       public  : 
          wikilink   (  std  ::  string   const  &   name  );     // = _ZN9wikipedia7article8wikilinkC1ERKSs 
       }; 
     }; 
  } 

Все искаженные символы начинаются с _Z(обратите внимание, что идентификатор, начинающийся с подчеркивания, за которым следует заглавная буква, является зарезервированным идентификатором в C, поэтому можно избежать конфликта с идентификаторами пользователя); для вложенных имен (включая пространства имен и классы) за ним следует N, затем серия пар <length, id> (длина равна длине следующего идентификатора) и, наконец, E. Например, wikipedia::article::format становится:

_ZN9wikipedia7article6formatE
 

Для функций за этим следует информация о типе; как format() это void функция, это просто v; следовательно:

_ZN9wikipedia7article6formatEv
 

Для print_to, стандартный тип std::ostream (что представляет собой определение типа для std::basic_ostream<char, std::char_traits<char> >) используется специальный псевдоним So; поэтому ссылка на этот тип RSo, полное имя функции:

_ZN9wikipedia7article8print_toERSSo
 

Как разные компиляторы искажают одни и те же функции [ править ]

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

Компилятор void h(int) void h(int, char) void h(void)
Intel C++ 8.0 для Linux _Z1hi _Z1hic _Z1hv
HP aC++ A.05.55 IA-64
И EWARM C++
GCC 3.x и выше
Clang 1.x и выше [3]
ОКС 2.9. Икс h__Fi h__Fic h__Fv
HP aC++ A.03.45 PA-RISC
Microsoft Visual C++ v6-v10 ( искажение деталей ) ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
Цифровой Марс C++
Борланд С++ v3.1 @h$qi @h$qizc @h$qv
OpenVMS C++ v6.5 (режим ARM) H__XI H__XIC H__XV
OpenVMS C++ v6.5 (режим ANSI) CXX$__7H__FIC26CDH77 CXX$__7H__FV2CB06E8
OpenVMS С++ X7.1 IA-64 CXX$_Z1HI2DSQ26A CXX$_Z1HIC2NP3LI4 CXX$_Z1HV0BCA19V
СанПро CC __1cBh6Fi_v_ __1cBh6Fic_v_ __1cBh6F_v_
Tru64 C++ v6.5 (режим ARM) h__Xi h__Xic h__Xv
Tru64 C++ v6.5 (режим ANSI) __7h__Fi __7h__Fic __7h__Fv
Ватком С++ 10.6 W?h$n(i)v W?h$n(ia)v W?h$n()v

Примечания:

  • Компилятор Compaq C++ для OpenVMS VAX и Alpha (но не IA-64) и Tru64 UNIX имеет две схемы искажения имен. Исходная предстандартная схема известна как модель ARM и основана на искажении имен, описанном в аннотированном справочном руководстве C++ (ARM). С появлением новых функций в стандарте C++, в частности шаблонов , схема ARM становилась все более и более непригодной — она не могла кодировать определенные типы функций или создавать одинаково искаженные имена для разных функций. Поэтому он был заменен более новой моделью Американского национального института стандартов (ANSI), которая поддерживала все функции шаблона ANSI, но не имела обратной совместимости.
  • В IA-64 существует стандартный двоичный интерфейс приложений (ABI) (см. внешние ссылки ), который определяет (помимо прочего) стандартную схему изменения имен и используется всеми компиляторами IA-64. GNU GCC 3. x дополнительно принял схему изменения имен, определенную в этом стандарте, для использования на других платформах, отличных от Intel.
  • Visual Studio и Windows SDK включают программу. undname который печатает прототип функции в стиле C для заданного искаженного имени.
  • В Microsoft Windows компилятор Intel [4] и Кланг [5] использует преобразование имен Visual C++ для совместимости.

Обработка символов C при связывании с C++ [ править ]

Работа общей идиомы C++:

#ifdef __cplusplus 
 extern   "C"   { 
 #endif 
     /* ... */ 
 #ifdef __cplusplus 
 } 
 #endif 

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

Например, стандартная библиотека строк, <string.h>, обычно содержит что-то вроде:

#ifdef __cplusplus 
 extern   "C"   { 
 #endif 

 void   *  memset   (  void   *  ,   int  ,   size_t  ); 
  char   *  strcat   (  char   *  ,   const   char   *  ); 
  int     strcmp   (  const   char   *  ,   const   char   *  ); 
  char   *  strcpy   (  char   *  ,   const   char   *  ); 

  #ifdef __cplusplus 
 } 
 #endif 

Таким образом, такой код, как:

if   (  strcmp  (  argv  [  1  ],   "-x"  )   ==   0  )  
     strcpy  (  a  ,   argv  [  2  ]); 
  еще  
     memset   (  a  ,   0  ,   sizeof  (  a  )); 

использует правильный, неиспорченный strcmp и memset. Если extern "C" не использовался, компилятор (SunPro) C++ выдал бы код, эквивалентный:

if   (  __1cGstrcmp6Fpkc1_i_  (  argv  [  1  ],   "-x"  )   ==   0  )  
     __1cGstrcpy6Fpcpkc_0_  (  a  ,   argv  [  2  ]); 
  еще  
     __1cGmemset6FpviI_0_   (  a  ,   0  ,   sizeof  (  a  )); 

Поскольку эти символы не существуют в библиотеке времени выполнения C ( например, libc), возникнут ошибки компоновки.


Стандартизированное искажение имен в C++ [ править ]

Казалось бы, стандартизированное изменение имен в языке C++ приведет к большей совместимости между реализациями компилятора. Однако такой стандартизации самой по себе недостаточно, чтобы гарантировать совместимость компиляторов C++, и она может даже создать ложное впечатление, что совместимость возможна и безопасна, хотя на самом деле это не так. Изменение имен — это лишь одна из нескольких деталей двоичного интерфейса приложения (ABI), которые должны быть решены и соблюдены реализацией C++. Другие аспекты ABI, такие как обработка исключений , макет виртуальной таблицы , структура и заполнение кадров стека , также приводят к несовместимости различных реализаций C++. Кроме того, требование определенной формы искажения может вызвать проблемы для систем, в которых ограничения реализации (например, длина символов) диктуют конкретную схему искажения. Стандартизированное требование по изменению имен также предотвратит реализацию, в которой искажение вообще не требуется — например, компоновщик, понимающий язык C++.

Поэтому стандарт C++ не пытается стандартизировать искажение имен. Напротив, Справочное руководство по C++ с аннотациями (также известное как ARM , ISBN   0-201-51459-1 , раздел 7.2.1c) активно поощряет использование различных схем искажения для предотвращения связывания, когда другие аспекты ABI несовместимы.

Тем не менее, как подробно описано в разделе выше, на некоторых платформах [6] Полный C++ ABI был стандартизирован, включая искажение имен.

Реальные последствия искажения имен C++ [ править ]

Поскольку символы C++ обычно экспортируются из DLL и общих объектных файлов, схема искажения имен — это не просто внутренняя проблема компилятора. Разные компиляторы (или во многих случаях разные версии одного и того же компилятора) создают такие двоичные файлы с разными схемами оформления имен, а это означает, что символы часто не разрешаются, если компиляторы, используемые для создания библиотеки, и использующая ее программа использовали разные схемы. Например, если система с несколькими установленными компиляторами C++ (например, GNU GCC и компилятор поставщика ОС) желает установить библиотеки Boost C++ , ее придется скомпилировать несколько раз (один раз для GCC и один раз для компилятора поставщика).

В целях безопасности полезно, чтобы компиляторы, создающие несовместимые объектные коды (коды, основанные на разных ABI, например, в отношении классов и исключений), использовали разные схемы искажения имен. Это гарантирует, что эти несовместимости будут обнаружены на этапе компоновки, а не при запуске программного обеспечения (что может привести к неявным ошибкам и серьезным проблемам со стабильностью).

По этой причине украшение имени является важным аспектом любого ABI , связанного с C++ .

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

Разборка с помощью c++filt [ править ]

$  c++filt   -n   _ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_ 
  Map<StringName, Ref<GDScript>, Comparator<StringName>, DefaultAllocator>::has(StringName const&) const 

Деманглирование через встроенный GCC ABI [ править ]

#include   <stdio.h> 
 #include   <stdlib.h> 
 #include   <cxxabi.h> 

 int   main  ()   { 
	 const   char   *  mangled_name   =   "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_"  ; 
	  int   статус   =   -1  ; 
	  char   *  demangled_name   =   abi  ::  __cxa_demangle  (  искаженное_имя  ,   NULL  ,   NULL  и   статус  )  ; 
	  printf  (  "Распутано: %s  \n  "  ,   demangled_name  ); 
	  бесплатно  (  деманглированное_имя  ); 
	  вернуть   0  ; 
  } 

Выход:

Demangled: Map<StringName, Ref<GDScript>, Comparator<StringName>, DefaultAllocator>::has(StringName const&) const

Ява [ править ]

В Java подпись метода или класса содержит его имя , типы аргументов метода и возвращаемое значение, если это применимо. Формат подписей документирован, поскольку язык, компилятор и формат файла .class были разработаны вместе (и с самого начала учитывались объектная ориентация и универсальная совместимость).

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

Область действия анонимных классов ограничена их родительским классом, поэтому компилятор должен создать «полное» общедоступное имя для внутреннего класса , чтобы избежать конфликта, когда другие классы с тем же именем (внутренним или нет) существуют в том же пространстве имен. Точно так же анонимные классы должны иметь «поддельные» общедоступные имена, сгенерированные для них (поскольку концепция анонимных классов существует только в компиляторе, а не во время выполнения). Итак, компилируем следующую Java-программу:

общественный   класс   foo   { 
     класса   панель   { 
         public   int   x  ; 
      } 

     public   void   zark   ()   { 
         Object   f   =   new   Object   ()   { 
             public   String   toString  ()   { 
                 return   "hello"  ; 
              } 
         }; 
      } 
 } 

создаст три файла .class :

  • foo.class , содержащий основной (внешний) класс foo
  • foo$bar.class , содержащий именованный внутренний класс foo.bar
  • foo$1.class , содержащий анонимный внутренний класс (локальный для метода foo.zark )

Все эти имена классов действительны (поскольку символы $ разрешены в спецификации JVM), и эти имена «безопасны» для генерации компилятором, поскольку определение языка Java рекомендует не использовать символы $ в обычных определениях классов Java.

Разрешение имен в Java еще более усложняется во время выполнения, поскольку полные имена классов уникальны только внутри конкретного экземпляра загрузчика классов . Загрузчики классов упорядочены иерархически, и каждый поток в JVM имеет так называемый контекстный загрузчик классов, поэтому в случаях, когда два разных экземпляра загрузчика классов содержат классы с одинаковым именем, система сначала пытается загрузить класс, используя корневой (или системный) загрузчик классов. а затем спускается по иерархии к загрузчику классов контекста.

Собственный интерфейс Java [ править ]

Java Native Interface , встроенная поддержка методов Java, позволяет программам на языке Java вызывать программы, написанные на другом языке (обычно C или C++). Здесь есть две проблемы с разрешением имен, ни одна из которых не реализована стандартизированным образом:

  • Преобразование имен JVM в собственное имя — это кажется более стабильным, поскольку Oracle делает свою схему общедоступной. [7]
  • Обычное искажение имен C++ — см. выше.

Питон [ править ]

В Python искажение используется для атрибутов класса, которые нежелательно использовать в подклассах. [8] которые обозначаются как таковые путем присвоения им имени с двумя или более начальными подчеркиваниями и не более чем одним завершающим подчеркиванием. Например, __thing будет искалечен, как и ___thing и __thing_, но __thing__ и __thing___не будет. Среда выполнения Python не ограничивает доступ к таким атрибутам, искажение предотвращает конфликты имен только в том случае, если производный класс определяет атрибут с тем же именем.

При обнаружении искаженных имен атрибутов Python преобразует эти имена, добавляя к началу одно подчеркивание и имя включающего класса, например:

>>>  class   Test  : 
 ...      def   __mangled_name  (  self  ): 
 ...          pass 
 ...      defnormal_name   в  (  self  ): 
 ...          pass 
 >>>  t   =   Test  ) 
 >>>  [  attr   для   attr   каталоге   (  (  t  )   if   "name"   в   attr  ] 
 ['_Test__mangled_name', 'normal_name'] 

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

Турбо Паскаль, Delphi [ править ]

Чтобы избежать искажения имен в Паскале, используйте:

экспортирует 
   myFunc   имя   'myFunc'  , 
   myProc   имя   'myProc'  ; 

Бесплатный Паскаль [ править ]

Free Pascal поддерживает перегрузку функций и операторов, поэтому для поддержки этих функций он также использует преобразование имен. С другой стороны, Free Pascal способен вызывать символы, определенные во внешних модулях, созданных на другом языке, и экспортировать свои собственные символы для вызова на другом языке. Для получения дополнительной информации обратитесь к главам 6.2 и 7.1 Руководства программиста Free Pascal .

Фортран [ править ]

Искажение имен также необходимо в компиляторах Фортрана , поскольку язык нечувствителен к регистру . Дальнейшие требования к искажению были наложены позже в ходе развития языка из-за добавления модулей и других функций в стандарт Fortran 90. которую необходимо решать при вызове библиотек Фортрана, таких как LAPACK , из других языков, таких как C. В частности, искажение регистра является распространенной проблемой ,

Из-за нечувствительности к регистру имя подпрограммы или функции FOOдолжен быть преобразован компилятором в стандартизированный регистр и формат, чтобы он был связан одинаково независимо от регистра. Разные компиляторы реализовали это по-разному, и никакой стандартизации не произошло. Компиляторы Fortran для AIX и HP-UX преобразуют все идентификаторы в нижний регистр. foo, а компиляторы Fortran Cray и Unicos преобразовывали идентификаторы в верхний регистр. FOO. Компилятор GNU g77 преобразует идентификаторы в нижний регистр плюс подчеркивание. foo_, за исключением того, что идентификаторы уже содержат подчеркивание FOO_BAR добавить два подчеркивания foo_bar__в соответствии с соглашением, установленным f2c . Многие другие компиляторы, включая от Silicon Graphics (SGI) компиляторы IRIX , GNU Fortran и Intel (кроме Microsoft Windows), преобразуют все идентификаторы в нижний регистр плюс подчеркивание ( компилятор Fortran от foo_ и foo_bar_, соответственно). В Microsoft Windows компилятор Intel Fortran по умолчанию использует верхний регистр без подчеркивания. [9]

Идентификаторы в модулях Fortran 90 необходимо дополнительно изменить, поскольку одно и то же имя процедуры может встречаться в разных модулях. Поскольку стандарт Fortran 2003 требует, чтобы имена процедур модуля не конфликтовали с другими внешними символами, [10] компиляторы обычно используют имя модуля и имя процедуры с отдельным маркером между ними. Например:

модуль  m  
 содержит 
    целочисленную  функцию  пять  () 
       пять   =   5 
    конечная функция  пять 
 конечный модуль  м 

В этом модуле имя функции будет изменено как __m_MOD_five (например, GNU Фортран), m_MP_five_ (например, ifort от Intel), m.five_ (например, Sun95 от Oracle) и т. д. Поскольку Фортран не позволяет перегружать имя процедуры, а вместо этого использует общие блоки интерфейса и общие процедуры с привязкой к типу, искаженные имена не должны содержать подсказки об аргументах.

Параметр BIND Fortran 2003 отменяет любые изменения имен, выполняемые компилятором, как показано выше .

Ржавчина [ править ]

по умолчанию искажаются Имена функций в Rust . Однако это можно отключить с помощью #[no_mangle]атрибут функции. Этот атрибут можно использовать для экспорта функций в C, C++ или Objective-C . [11] Далее, наряду с #[start] атрибут функции или #[no_main] crate, он позволяет пользователю определить точку входа в программу в стиле C. [12]

В Rust используется множество версий схем преобразования символов, которые можно выбрать во время компиляции с помощью -Z symbol-mangling-versionвариант. Определены следующие манглеры:

  • legacyИзменение стиля C++ на основе ABI Itanium IA-64 C++. Символы начинаются с _ZN, а хеши имен файлов используются для устранения неоднозначности. Используется начиная с Rust 1.9. [13]
  • v0Улучшенная версия устаревшей схемы с изменениями для Rust. Символы начинаются с _R. Полиморфизм может быть закодирован. Функции не имеют закодированных типов возвращаемых значений (в Rust нет перегрузки). Имена в Юникоде используют модифицированный Punycode . Сжатие (обратная ссылка) использует байтовую адресацию. Используется начиная с Rust 1.37. [14]

Примеры представлены в Rust. symbol-names тесты. [15]

Objective-C [ править ]

существуют две формы метода По сути, в Objective-C : метод класса («статический») и метод экземпляра . Объявление метода в Objective-C имеет следующую форму:

+ (  тип возвращаемого значения  )  имя  0  :  параметр  0   имя  1  :  параметр  1  ... 
  – (  тип возвращаемого значения  )  имя  0  :  параметр  0   имя  1  :  параметр  1  ... 
 

Методы класса обозначаются знаком «+», методы экземпляра — знаком «-». Типичное объявление метода класса может выглядеть так:

+   (  id  )   initWithX:   (  int  )   число   иY:   (  int  )   число  ; 
  +   (  id  )   новый  ; 

С методами экземпляра, выглядящими так:

-   (  id  )   значение  ; 
  -   (  id  )   setValue:   (  id  )   new_value  ; 

Каждое из этих объявлений метода имеет определенное внутреннее представление. При компиляции каждый метод получает имя по следующей схеме для методов класса:

_c_  Имя_класса  имя  0  _  1  _  ... 
 

и это, например, методы:

_i_  Имя_класса  имя  0  _  1  _  ... 
 

Двоеточия в синтаксисе Objective-C преобразуются в символы подчеркивания. Итак, метод класса Objective-C + (id) initWithX: (int) number andY: (int) number;, если принадлежит к Point класс переводится как _c_Point_initWithX_andY_и метод экземпляра (принадлежащий одному и тому же классу) - (id) value; перевел бы на _i_Point_value.

Таким образом помечаются каждый из методов класса. Однако поиск метода, на который может реагировать класс, был бы утомительным, если бы все методы были представлены таким образом. Каждому из методов присваивается уникальный символ (например, целое число). Такой символ известен как селектор . В Objective-C можно напрямую управлять селекторами — в Objective-C они имеют определенный тип — SEL.

Во время компиляции строится таблица, отображающая текстовое представление, например: _i_Point_value, к селекторам (которым присвоен тип SEL). Управление селекторами более эффективно, чем управление текстовым представлением метода. Обратите внимание, что селектор соответствует только имени метода, а не классу, к которому он принадлежит: разные классы могут иметь разные реализации метода с одним и тем же именем. По этой причине реализациям метода также присваивается определенный идентификатор, известный как указатели реализации, а также тип. IMP.

Отправки сообщений кодируются компилятором как вызовы id objc_msgSend (id receiver, SEL selector, ...) функция или один из ее кузенов, где receiver является получателем сообщения и SELопределяет метод для вызова. Каждый класс имеет свою собственную таблицу, которая сопоставляет селекторы с их реализациями — указатель реализации указывает, где в памяти находится реализация метода. Существуют отдельные таблицы для методов класса и экземпляра. Помимо хранения в SEL к IMP таблицы поиска, функции по существу анонимны.

The SELзначение селектора не различается между классами. Это обеспечивает полиморфизм .

Среда выполнения Objective-C хранит информацию о типах аргументов и возвращаемых значений методов. Однако эта информация не является частью имени метода и может варьироваться от класса к классу.

Поскольку Objective-C не поддерживает пространства имен , нет необходимости искажать имена классов (которые появляются в виде символов в сгенерированных двоичных файлах).

Свифт [ править ]

Swift хранит метаданные о функциях (и многом другом) в искаженных символах, ссылающихся на них. Эти метаданные включают имя функции, атрибуты, имя модуля, типы параметров, тип возвращаемого значения и многое другое. Например:

Искаженное имя метода func calculate(x: int) -> int из MyClass класс в модуле test является _TFC4test7MyClass9calculatefS0_FT1xSi_Si, на Свифт 2014 года. Компоненты и их значения следующие: [16]

  • _T: префикс для всех символов Swift. Все начнется с этого.
  • F: Функция без каррирования.
  • C: Функция класса, т.е. метод
  • 4test: имя модуля с префиксом его длины.
  • 7MyClass: Имя класса, которому принадлежит функция, с префиксом ее длины.
  • 9calculate: имя функции с префиксом ее длины.
  • f: Атрибут функции. В данном случае «f» означает нормальную функцию.
  • S0: Обозначает тип первого параметра (а именно экземпляра класса) как первый в стеке типов (здесь MyClass не является вложенным и поэтому имеет индекс 0).
  • _FT: начинается список типов кортежа параметров функции.
  • 1x: Внешнее имя первого параметра функции.
  • Si: указывает встроенный тип Swift.Int для первого параметра.
  • _Si: Тип возвращаемого значения: снова Swift.Int.

Исправление версий, начиная с Swift 4.0, официально задокументировано. Он сохраняет некоторое сходство с Itanium. [17]

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

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

  1. ^ «Двоичный интерфейс приложения» . Дланг.орг . Проверено 19 мая 2020 г.
  2. ^ Райнер, Шютце (20 декабря 2017 г.). «Новомодное искажение имени Ди» . Блог D. Проверено 19 мая 2020 г.
  3. ^ Clang — Возможности и цели: совместимость с GCC , 15 апреля 2013 г.
  4. ^ JBIntel_deleted_06032015. «Различия OBJ между компилятором Intel и компилятором VC» . программное обеспечение.intel.com . {{cite web}}: CS1 maint: числовые имена: список авторов ( ссылка )
  5. ^ «Совместимость MSVC» . Проверено 13 мая 2016 г.
  6. ^ «Itanium C++ ABI, раздел 5.1. Внешние имена (также известные как искажение)» . Проверено 16 мая 2016 г.
  7. ^ «Обзор конструкции» . docs.oracle.com .
  8. ^ «PEP 8 — Руководство по стилю для кода Python» .
  9. ^ «Краткий обзор проблем смешанного языка» . Пользовательское и справочное руководство по компилятору Intel Fortran 15.0 . Корпорация Интел . Проверено 17 ноября 2014 г.
  10. ^ «Библиотека документации» .
  11. ^ «Интерфейс внешних функций # Вызов кода Rust из C» . Руководство по ржавчине . www.rust-lang.org . Проверено 13 мая 2016 г.
  12. ^ «Нет стандартной библиотеки» . Руководство по ржавчине . www.rust-lang.org . Проверено 13 мая 2016 г.
  13. ^ «rust/src/librustc_codegen_utils/symbol_names/legacy.r.rs по адресу 57e1da59cd0761330b4ea8d47b16340a78eeafa9 · ржавчина-lang/rust · GitHub» . Гитхаб . 3 ноября 2021 г.
  14. ^ «Искажение символа ржавчины» . Книга Rust RFC .
  15. ^ «Rust 1.42.0: src/test/ui/symbol-names» . Гитхаб . Проверено 20 марта 2020 г.
  16. ^ «mikeash.com: Пятничные вопросы и ответы 15 августа 2014 г.: Искажение имен в Swift» . mikeash.com .
  17. ^ "apple/swift: mangling.rst" . Гитхаб . 3 ноября 2021 г.

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

Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: EBDDA8FE192275529C2A3F8511C7E64A__1714527900
URL1:https://en.wikipedia.org/wiki/Name_mangling
Заголовок, (Title) документа по адресу, URL1:
Name mangling - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)