我试图在明显不可移植但不是魔法的C中写出相当于C的typeID.对于Itanium ABI(在Linux / Mac上使用),它非常简单:
const std::type_info& dynamicast_typeID(voID *mdo){ std::type_info **vptr = *reinterpret_cast<std::type_info ***>(mdo); std::type_info *typeinfo_ptr = vptr[-1]; return *typeinfo_ptr;}
所以现在我正在看64位的MSVC ABI,然后对它说,我很难过.对于非常简单的类,以偏移0处的vfptr开头的类,它几乎和Itanium一样简单:
const std::type_info& dynamicast_typeID(voID *mdo){ int *rtti_complete_object_locator = ((int ***)mdo)[0][-1]; char *result = (char *) rtti_complete_object_locator; result -= rtti_complete_object_locator[5]; result += rtti_complete_object_locator[3]; return *(std::type_info*)result;}
(此代码基于the Wine project’s __RTtypeid
.)
问题是某些C类不是以偏移0处的vfptr开头的!有时他们从vbptr开始.
struct Class1 { virtual ~Class1() {} };struct Class2 : virtual Class1 {};
Class1以vfptr开头; Class2以vbptr开头.
当一个类以vbptr开头时,我相信它的第一个虚拟基础子对象(它在布局顺序中的第一个,因此它的“最活泼的”)总是会在其偏移0处有一个vfptr.所以如果我知道我’在处理以vbptr开头的类时,我想这样做:
const std::type_info& dynamicast_typeID_for_vbptr_class(voID *mdo){ int first_vbase_offset = ((int**)mdo)[0][1]; mdo = (char*)mdo + first_vbase_offset; int *rtti_complete_object_locator = ((int ***)mdo)[0][-1]; char *result = (char *) rtti_complete_object_locator; result -= rtti_complete_object_locator[5]; result += rtti_complete_object_locator[3]; return *(std::type_info*)result;}
我已经确定了MSVC does actually generate相当于
if constexpr(IS_VBPTR_CLASS) { int first_vbase_offset = ((int**)mdo)[0][1]; mdo = (char*)mdo + first_vbase_offset; } return __RTtypeID(mdo);
当编译C表达式typeID(x)时 – 其中IS_VBPTR_CLASS是伪代码,“编译器根据x的静态类型以及编译器知道每种类型的布局这一事实神奇地知道x是否具有vbptr.”
但是,在我的情况下,我不知道x的静态类型,即使我这样做,我也不知道如何找出(从C中,使用模板元编程)x是否以vbptr开头.
最后,我继续前进并稍微捏了一下
const std::type_info& dynamicast_typeID(voID *mdo){ while (((int**)mdo)[0][0] == 0) { mdo = (char *)mdo + ((int**)mdo)[0][1]; } int *rtti_complete_object_locator = ((int ***)mdo)[0][-1]; char *result = (char *)complete_object_locator; result -= rtti_complete_object_locator[5]; result += rtti_complete_object_locator[3]; return *(std::type_info*)result;}
只发现存储在vftable中的“Class1中的Class1”的typeinfo保存了子对象类型Class1的typeinfo,而不是最派生类型的Class2!所以还有另一块拼图丢失了.
所以我的问题简而言之:给定(voID *)& object_of_type_class2,如何检索typeID(Class2)?
解决方法 我有一些现在有用的东西!函数dynamicast_to_mdo相当于dynamic_cast< voID *>(p) – 它调整p以指向其最派生的对象.
函数dynamicast_typeID相当于typeID(p) – 它从p的vtable中获取typeinfo.我只是在使用我在问题中给出的软糖/黑客,我实际上不确定为什么我几个小时前得到了错误的答案;我想当我看到错误的typeinfo时,可能是因为我不小心试图将悬挂引用的typeID取为已销毁的堆栈变量.
// 64-bit MSVC ABIvoID *dynamicast_to_mdo(voID *p){ if (((int**)p)[0][0] == 0) { p = (char *)p + ((int**)p)[0][1]; } int *complete_object_locator = ((int ***)p)[0][-1]; int mdoffset = complete_object_locator[1]; voID *adjusted_this = static_cast<char *>(p) - mdoffset; return adjusted_this;}// 64-bit MSVC ABIconst std::type_info& dynamicast_typeID(voID *p){ if (((int**)p)[0][0] == 0) { p = (char *)p + ((int**)p)[0][1]; } int *complete_object_locator = ((int ***)p)[0][-1]; char *result = (char *)complete_object_locator; result -= complete_object_locator[5]; result += complete_object_locator[3]; return *(const std::type_info*)result;}总结
以上是内存溢出为你收集整理的c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?全部内容,希望文章能够帮你解决c – 在MSVC ABI中,如何只给出一个(void *)可靠地找到vtable?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)