给定一个含有虚函数的对象的地址,找到对应的类名,不同平台下方法也不同,这是由于RTTI实现并没有统一的标准。
Linux:
#include <iostream>
#include <typeinfo>class Person
{
public:virtual void func(){std::cout << typeid(*this).name() << std::endl;}
};const char* ClassName(void* address)
{uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);std::type_info* ti = reinterpret_cast<std::type_info*>(*(vftablePtr - 1));return ti->name();
}int main()
{Person p;std::cout << ClassName(&p) << std::endl;std::cout << typeid(p).name() << std::endl;
}
运行结果:
6Person
6Person
其中,Person
代表类名,6
表示的是类名的长度。
Windows x86:
#include <iostream>
#include <typeinfo>class Person
{
public:virtual void func(){std::cout << typeid(*this).name() << std::endl;}
};const char* ClassMangledName(void* address)
{uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);uintptr_t* rttiObject = reinterpret_cast<uintptr_t*>(*(vftablePtr - 1));std::type_info* ti = reinterpret_cast<std::type_info*>(*(rttiObject + 3));const char* className = ti->name();return className;
}int main()
{Person p;std::cout << ClassMangledName(&p) << std::endl;std::cout << typeid(p).name() << std::endl;
}
运行结果:
class Person
class Person
Windows x64:
#include <iostream>
#include <ehdata.h>
#include <rttidata.h>class Person
{
public:virtual void func(){std::cout << typeid(*this).name() << std::endl;}
};const char* ClassMangledName(void* address)
{uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);_RTTICompleteObjectLocator* rttiLocator = reinterpret_cast<_RTTICompleteObjectLocator*>(*(vftablePtr - 1));uintptr_t imageBase = reinterpret_cast<uintptr_t>(rttiLocator) - rttiLocator->pSelf;TypeDescriptor* typeDescriptor = reinterpret_cast<TypeDescriptor*>(imageBase + rttiLocator->pTypeDescriptor);const char* classMangledName = typeDescriptor->name;return classMangledName;
}int main()
{Person p;std::cout << ClassMangledName(&p) << std::endl;std::cout << typeid(p).raw_name() << std::endl;
}
运行结果:
.?AVPerson@@
.?AVPerson@@
打印的结果是raw name,也就是未修饰的名字。