Microsoft C++ Name Mangling Scheme

version 1.1 (November 25, 2005)

This document discusses C++ name mangling scheme used by Microsoft. I think this is the most complete document about this scheme currently.

Author

This document is maintained by Kang Seonghoon aka Tokigun.

If you want to discuss about this scheme or document please mail me: <xxxxxxx at gmail dot com> where xxxxxxx is tokigun.

And sorry for my poor English ;)

Reference

Even though I could disassemble dbghelp.dll(or msvcrt.dll), I didn't do it because of the legal issues. So I used only UnDecorateSymbolName function to analysis this scheme.

Also I learned the basic scheme from the following source:

Some feature of this scheme depends on Microsoft's C++ extension, such as Managed C++. Browse MSDN for more information.

Basic Structure

As you know, all mangled C++ name starts with ?. Because all mangled C name starts with alphanumeric characters, @(at-sign) and _(underscore), C++ name can be distinguished from C name.

Structure of mangled name looks like this:

Function

Type information in function name generally looks like this:

Data

Type information in data name looks like this:

Elements

Mangled name contains a lot of elements have to be discussed.

Name

Qualified name consists of the following fragments:

Qualification is written in reversed order. For example myclass::nested::something becomes something@nested@myclass@@.

Name Fragment

A fragment of name is simply represented as the name with trailing @.

Special Name

Special name is represented as the code with preceding ?. Most of special name is constructor, destructor, operator and internal symbol. Below is a table for known codes.

CodeMeaning with no _Meaning with preceding _Meaning with preceding two _s
0Constructoroperator/=
1Destructoroperator%=
2operator newoperator>>=
3operator deleteoperator<<=
4operator=operator&=
5operator>>operator|=
6operator<<operator^=
7operator!`vftable'
8operator==`vbtable'
9operator!=`vcall'
Aoperator[]`typeof'`managed vector constructor iterator'
Boperator returntype[1]`local static guard'`managed vector destructor iterator'
Coperator->`string' (Unknown)[2]`eh vector copy constructor iterator'
Doperator*`vbase destructor'`eh vector vbase copy constructor iterator'
Eoperator++`vector deleting destructor'
Foperator--`default constructor closure'
Goperator-`scalar deleting destructor'
Hoperator+`vector constructor iterator'
Ioperator&`vector destructor iterator'
Joperator->*`vector vbase constructor iterator'
Koperator/`virtual displacement map'
Loperator%`eh vector constructor iterator'
Moperator<`eh vector destructor iterator'
Noperator<=`eh vector vbase constructor iterator'
Ooperator>`copy constructor closure'
Poperator>=`udt returning' (prefix)
Qoperator,Unknown[3]
Roperator()RTTI-related code (see below)
Soperator~`local vftable'
Toperator^`local vftable constructor closure'
Uoperator|operator new[]
Voperator&&operator delete[]
Woperator||
Xoperator*=`placement delete closure'
Yoperator+=`placement delete[] closure'
Zoperator-=

Prefix _P is used as ?_PX, though I don't know about it. [TODO: what is udt? user defined type?]

Below is RTTI-related code (all starting with _R). Some codes have trailing parameters.

CodeMeaningTrailing Parameters
_R0type `RTTI Type Descriptor'Data type type.
_R1`RTTI Base Class Descriptor at (a,b,c,d)'Four encoded numbers a, b, c and d.
_R2`RTTI Base Class Array'None.
_R3`RTTI Class Hierarchy Descriptor'None.
_R4`RTTI Complete Object Locator'None.

Name with Template Arguments

Name fragment starting with ?$ has template arguments. This kind of name looks like this:

For example, we assume the following prototype.

void __cdecl abc<def<int>,void*>::xyz(void);

Name of this function can be obtained by the following process:

abc<def<int>,void*>::xyz
xyz@ abc<def<int>,void*> @
xyz@ ?$abc@ def<int> void* @ @
xyz@ ?$abc@ V def<int> @ PAX @ @
xyz@ ?$abc@ V ?$def@H@ @ PAX @ @
xyz@?$abc@V?$def@H@@PAX@@

So mangled name for this function is ?xyz@?$abc@V?$def@H@@PAX@@YAXXZ.

Numbered Namespace

In qualification, numbered namespace is represented as preceding ? and unsigned number. UnDecorateSymbolName function returns something like `42' for this kind of input.

Exceptionally if numbered namespace starts with ?A it becomes anonymous namespace (`anonymous namespace').

Well, of course I'm not sure what it is. [TODO: what is exact meaning and name? I don't think its name is really "numbered namespace".]

Back Reference

Decimal digits 0 to 9 refers to first shown name fragment to 10th shown name fragment. Referred name fragment can be normal name fragment or name fragment with template arguments. For example, in alpha@?1beta@@(beta::`2'::alpha) 0 refers to alpha@, and 1(not 2) refers to beta@.

Generally back reference table is kept during mangling process. It means you can use back reference to function name in function arguments (shown later than function name). However, in template argument list back reference table is separately created.

For example, assume ?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@(std::basic_string<unsigned short, std::char_traits<unsigned short>, std::allocator<unsigned short> >). In std::basic_string<...>, 0 refers to basic_string@, 1 refers to ?$char_traits@G@, and 2 refers to std@. This relation doesn't change wherever it is.

Encoded Number

In name mangling, representation of number is needed sometimes (e.g. array indices). There are simple rules to represent number:

Data Type

The table below shows various data type and modifiers.

CodeMeaning with no _Meaning with preceding _
?Type modifier, Template parameter
$Type modifier, Template parameter[4]__w64 (prefix)
0-9Back reference
AType modifier (reference)
BType modifier (volatile reference)
Csigned char
Dchar__int8
Eunsigned charunsigned __int8
Fshort__int16
Gunsigned shortunsigned __int16
Hint__int32
Iunsigned intunsigned __int32
Jlong__int64
Kunsigned longunsigned __int64
L__int128
Mfloatunsigned __int128
Ndoublebool
Olong doubleArray
PType modifier (pointer)
QType modifier (const pointer)
RType modifier (volatile pointer)
SType modifier (const volatile pointer)
TComplex Type (union)
UComplex Type (struct)
VComplex Type (class)
WEnumerate Type (enum)wchar_t
Xvoid, Complex Type (coclass)Complex Type (coclass)
YComplex Type (cointerface)Complex Type (cointerface)
Z... (elipsis)

Actually void for X and elipsis for Z can be used only for terminator of argument list or pointer. Otherwise, X is used as cointerface.

Primitive & Extended Type

Primitive types are represented as one character, and extended types are represented as one character preceding _.

Back Reference

Decimal digits 0 to 9 refers to first shown type to 10th shown type in argument list. (It means return type cannot be referred.) Back reference can refer to any non-primitive type, including extended type. Of course back reference can refer to prefixed type such as PAVblah@@(class blah *), but cannot refer to prefixless type — say, Vblah@@ in PAVblah@@.

As back reference for name, in template argument list back reference table is separately created. Function argument list has no such scoping rule, though it can be confused sometimes. For example, assume P6AXValpha@@Vbeta@@@Z(void (__cdecl*)(class alpha, class beta)) is first shown non-primitive type. Then 0 refer to Valpha@@, 1 refer to Vbeta@@, and finally 2 refer to function pointer.

Type Modifier

Type modifier is used to make pointer or reference. Type modifier looks like this:

There is eight type of type modifier:

noneconstvolatileconst volatile
PointerPQRS
ReferenceAB
none?[5], $$C

For normal type, referred type info is data type. For function, it looks like the following. (It depends on CV-class modifier)

Complex Type (union, struct, class, coclass, cointerface)

Complex type looks like this:

Enumerate Type (enum)

Enumerate type starts with prefix W. It looks like this:

Real type for enum is represented as the following:

CodeCorresponding Real Type
0char
1unsigned char
2short
3unsigned short
4int (generally normal "enum")
5unsigned int
6long
7unsigned long

Array

Array (not pointer to array!) starts with prefix _O. It looks like this:

You can use multi-dimensional array like _OC_OBH, but only the outmost CV-class modifier is affected. (In this case _OC_OBH means int volatile [][], not int const [][])

Template Parameter

Template parameter is used to represent type and non-type template argument. It can be used in only template argument list.

The table below is a list of known template parameters. a, b, c represent encoded signed numbers, and x, y, z represent encoded unsigned numbers.

CodeMeaning
?xanonymous type template parameter x (`template-parameter-x')
$0ainteger value a
$2abreal value a × 10b-k+1, where k is number of decimal digits of a[7]
$Daanonymous type template parameter a (`template-parametera')
$Fab2-tuple {a,b} (unknown)
$Gabc3-tuple {a,b,c} (unknown)
$Hx(unknown)
$Ixy(unknown)
$Jxyz(unknown)
$Qaanonymous non-type template parameter a (`non-type-template-parametera')

Argument List

Argument list is a sequence of data types. List can be one of the following:

Template Argument List

Template argument list is same to argument list, except template parameters can be used.

CV-class Modifier

The following table shows CV-class modifiers.*

VariableFunction
noneconstvolatileconst volatile
noneAB, JC, G, KD, H, L6, 7
__based()MNOP_A, _B
MemberQ, U, YR, V, ZS, W, 0T, X, 18, 9
__based() Member2345_C, _D

CV-class modifier can have zero or more prefix:

PrefixMeaning
Etype __ptr64
F__unaligned type
Itype __restrict

Modifiers have trailing parameters as follows:

CV-class modifier is usually used in reference/pointer type, but it is also used in other place with some restrictions:

__based() Property

__based() property represents Microsoft's __based() attribute extension to C++. This property can be one of the following:

Function Property

Function property represents prototype of function. It looks like this:

The following table shows calling convention of function:

CodeExported?Calling Convention
ANo__cdecl
BYes__cdecl
CNo__pascal
DYes__pascal
ENo__thiscall
FYes__thiscall
GNo__stdcall
HYes__stdcall
INo__fastcall
JYes__fastcall
KNonone
LYesnone
MNo__clrcall

Argument list for throw() attribute is same to argument list, but if this list is Z, it means there is no throw() attribute. If you want to use throw() you have to use @ instead.

Function

Typical type information in function name looks like this:

The table below shows code for access level and function type:

nonestaticvirtualthunk
private:A, BC, DE, FG, H
protected:I, JK, LM, NO, P
public:Q, RS, TU, VW, X
noneY, Z

This kind of thunk function is always virtual, and used to represent logical this adjustor property, which means an offset to true this value in some multiple inheritance.

Data

Type information in data name looks like this:

The table below shows code for access level and storage class:

CodeMeaning
0Private static member
1Protected static member
2Public static member
3Normal variable
4Normal variable

CV-class modifier should not be function.

Thunk Function

There is several kind of thunk function. [TODO: a lot of thunk function!]


Footnotes

* Some tables contain two or more entries in one case. In this case, I tried to place more frequently used entry in the front. (But I'm not sure that this placement. Don't ask it for me!)

[1] Its meaning depends on return type of function. For instance, if this function returns int type then its name will be operator int.

[2] It seems structure after ?_C is different from other structure. I think this structure is represented as regular expression \?_C@_[0-9A-P]([0-9A-P][A-P]*)?@.*@, but I'm not sure.

[3] It can be EH-related code, but UnDecorateSymbolName function cannot demangle this.

[4] There is $$B prefix, but it seems that this prefix can be ignored.

[5] ? is valid only for type of data. Also ? should be the outmost type modifier. (?CPB is valid but PB?C is not.)

[6] ? and L can be complex type without any tag such as class, but it can also be a bug of the function.

[7] For example, $2HKLH@?2 means 3.1415 × 10-3 = 0.0031415, because HKLH@ means 31415 and ?2 means -3.

Copyright © 2005, Kang Seonghoon (Tokigun).