Внутренние имена

Функции, данные и объекты в программах на языках C и C++ внутренне представляются декорированными именами. Украшенное имя — это кодированная строка, созданная компилятором во время компиляции объекта, данных или определения функции. Оно содержит соглашения о вызовах, типы, параметры функции и другие сведения, а также имя. Это украшение имени, также известное как управление именами, помогает компоновщику найти правильные функции и объекты при связывании исполняемого файла.

Соглашения об именовании, украшенные, изменились в различных версиях Visual Studio, а также могут отличаться в разных целевых архитектурах. Чтобы правильно связаться с исходными файлами, созданными с помощью библиотек DLL и библиотек Visual Studio, C и C++, следует скомпилировать с помощью одного набора инструментов компилятора, флагов и целевой архитектуры.

Примечание.

Библиотеки, созданные Visual Studio 2015 или более поздней версии, могут использоваться приложениями, созданными с более поздними версиями Visual Studio до Visual Studio 2022. Дополнительные сведения см. в статье о совместимости двоичных файлов C++ между версиями Visual Studio.

Использование украшенных имен

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

При изменении имени функции, класса, соглашении о вызовах, типа возвращаемого значения или какого-либо параметра внутреннее имя также изменяется. В этом случае необходимо получить новое внутреннее имя и использовать его везде, где оно указано.

Декорирование имен также важно при компоновке с кодом, написанным на других языках программирования, или при использовании других компиляторов. Разные компиляторы используют различные соглашения о дополнении имен. Если исполняемый файл связывается с кодом, написанным на другом языке, необходимо уделить особое внимание сопоставлению экспортированных и импортированных параметров и соглашений о вызовах. Код языка сборки должен использовать декорированные имена MSVC и соглашения о вызовах, чтобы связаться с исходным кодом, написанным с помощью MSVC.

Формат декорированного имени C++

Внутреннее имя функции C++ содержит следующие сведения.

  • Имя функции.

  • Класс, в который входит функция, если это функция-член. Украшение может включать класс, который заключает класс, содержащий функцию, и т. д.

  • Пространство имен, к которому принадлежит функция, если она является частью пространства имен.

  • Типы параметров функции.

  • Соглашение о вызовах.

  • Тип значения, возвращаемого функцией.

  • Необязательный элемент целевого объекта. В ARM64EC объектах $$h тег вставляется в имя.

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

Внешнее имя Внутреннее имя
int a(char){int i=3;return i;}; ?a@@YAHD@Z
void __stdcall b::c(float){}; ?c@b@@AAGXM@Z

Формат декорированного имени C

Формат декорирования для функции C зависит от соглашения о вызовах, используемого в ее объявлении, как показано в следующей таблице. Это также формат оформления, используемый при объявлении кода C++ для extern "C" связывания. Соглашение о вызовах по умолчанию — __cdecl. В 64-разрядной среде C или extern "C" функции декорируются только при использовании соглашения о вызовах __vectorcall .

Соглашение о вызовах Оформление
__cdecl Ведущий подчеркивание (_)
__stdcall Начальный символ подчеркивания () и конечный знак (_@) и число байтов в списке параметров в десятичном разряде
__fastcall Начальный и конечный знаки (@) с десятичным числом, представляющим число байтов в списке параметров
__vectorcall Два конечных знака (@@), за которыми следует десятичное число байтов в списке параметров

Для функций ARM64EC с компоновкой C (будь то компилированная как C или с помощью extern "C"), она # добавляется к декорированному имени.

Просмотр украшенных имен

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

Использование листинга для просмотра внутренних имен

  1. Создайте список путем компиляции исходного файла, содержащего данные, объект или определение функции или прототип /FA с параметром компилятора (тип файла перечисления), заданным для сборки с исходным кодом (/FAs).

    Например, введите cl /c /FAs example.cpp в командной строке разработчика, чтобы создать файл перечисления. example.asm

  2. В результирующем файле перечисления найдите строку, которая начинается с PUBLIC и заканчивается точкой с запятой (;), за которой следует неоцененные данные или имя функции. Символ между PUBLIC и точкой с запятой — это украшенное имя.

Использование служебной программы DUMPBIN для просмотра внутренних имен

  1. Чтобы просмотреть экспортированные символы в OBJ или LIB-файле, введите dumpbin /exports <obj-or-lib-file> в командной строке разработчика.

  2. Чтобы найти внутреннюю форму символа, найдите внешнее имя в скобках. Декорированное имя находится в той же строке перед неоцененным именем.

Просмотр неоцененных имен

Можно использовать программу undname.exe для преобразования внутреннего имени в недекорированную форму. В этом примере показано, как это работает.

C:\>undname ?func1@a@@AAEXH@Z
Microsoft (R) C++ Name Undecorator
Copyright (C) Microsoft Corporation. All rights reserved.

Undecoration of :- "?func1@a@@AAEXH@Z"
is :- "private: void __thiscall a::func1(int)"

См. также

Дополнительные средства сборки MSVC
Использование extern для указания компоновки