注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

c++filt展示typeid的名字  

2013-07-07 01:23:56|  分类: Gcc源代码分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、问题展示
遇到一个问题,代码里使用了模板实例的动态转换方法,动态转换就是通过dynamic_cast的时候返回值为NULL,所以转换失败。如果是简单的问题,那么直接肉眼就可以看出来原因,但是如果说里面涉及了大量的宏、条件编译和C++中的高级宏—模板,此时定位问题的时候就比较麻烦,那么最为直接的方法就是看看那个对象到底是什么类型,这样结合当前的目标转换类型就可以确定问题的原因,此时我们就可以给出令人信服的方法。
二、解决的方法
直观的方法就是通过typeid(xxx).name来打印出这个对象真实的类型,或者说时它被创建的类型,或者说一个人的出身,这个是改变不了。我们从一个例子里展示一下效果
[root@Harry typename]# cat type.cpp
#include <stdio.h>
#include <typeinfo>

struct base
{
    int iHolder;
    virtual int foo() {return 0;}
};
template<typename type, int size>
struct derive : public base
{
    type arr[size];   
};
int foo(base * pbase)
{
    printf("typeid.name %s\n", typeid(*pbase).name());
    return 0;
}

int main()
{
    base b;
    foo(&b);
    derive<float, 20> d;
    foo(&d);
   
}
[root@Harry typename]# g++ type.cpp
[root@Harry typename]# ./a.out
typeid.name 4base
typeid.name 6deriveIfLi20EE
[root@Harry typename]# c++filt 6deriveIfLi20EE
6deriveIfLi20EE
[root@Harry typename]#
大家可以看到,C++filt没有将字符串反粉碎出来。这里大家要注意啊:typeid的参数必须是一个对指针取内容(dereference),如果只是简单的对指针本身执行typeid,,它的结果就是一个指定类型的字符串,它的结果是在编译的时候确定的。
另一方面,编译时指定的类型必须包含虚函数,如果没有,那动态转换的结果也是编译时确定的而不是动态确定的。
三、如何破
其实问题的解决办法非常简单,因为用自己简单的智商想一想,这样的需求应该是比较常见的,所以应该有通用的方法,所以打印一下c++filt的选项,还真有这个选项:
[root@Harry typename]# c++filt --help
Usage: c++filt [options] [mangled names]
Options are:
  [-_|--strip-underscore]     Ignore first leading underscore
  [-n|--no-strip-underscore]  Do not ignore a leading underscore (default)
  [-p|--no-params]            Do not display function arguments
  [-i|--no-verbose]           Do not show implementation details (if any)
  [-t|--types]                Also attempt to demangle type encodings
  [-s|--format {none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat}]
  [@<file>]                   Read extra options from <file>
  [-h|--help]                 Display this information
  [-v|--version]              Show the version information
Demangled names are displayed to stdout.
If a name cannot be demangled it is just echoed to stdout.
If no names are provided on the command line, stdin is read.
Report bugs to <http://bugzilla.redhat.com/bugzilla/>.
[root@Harry typename]# ./a.out | c++filt -t
typeid.name base
typeid.name derive<float, 20>

[root@Harry typename]#
四、gcc的实现
对于包含虚函数的对象,它的静态typeinfo字符串是直接和虚函数表绑定的,
[root@Harry typename]# cat type.s | c++filt
    .file    "type.cpp"
    .section    .text._ZNKSt9type_info4nameEv,"axG",@progbits,std::type_info::name() const,comdat
    .align 2
    .weak    std::type_info::name() const
    .type    std::type_info::name() const, @function
std::type_info::name() const:
.LFB6:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl    %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    movl    8(%ebp), %eax
    movl    4(%eax), %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
……
.LFE21:
    .size    main, .-main
    .weak    vtable for derive<float, 20>
    .section    .rodata._ZTV6deriveIfLi20EE,"aG",@progbits,vtable for derive<float, 20>,comdat
    .align 8
    .type    vtable for derive<float, 20>, @object

    .size    vtable for derive<float, 20>, 12
vtable for derive<float, 20>:
    .long    0
    .long    typeinfo for derive<float, 20>
    .long    base::foo()
    .weak    vtable for base
    .section    .rodata._ZTV4base,"aG",@progbits,vtable for base,comdat
    .align 8
    .type    vtable for base, @object
    .size    vtable for base, 12
vtable for base:
    .long    0
    .long    typeinfo for base
    .long    base::foo()
    .weak    typeinfo name for derive<float, 20>
    .section    .rodata._ZTS6deriveIfLi20EE,"aG",@progbits,typeinfo name for derive<float, 20>,comdat
    .type    typeinfo name for derive<float, 20>, @object
    .size    typeinfo name for derive<float, 20>, 16
typeinfo name for derive<float, 20>:
    .string    "6deriveIfLi20EE"
    .weak    typeinfo for derive<float, 20>

    .section    .rodata._ZTI6deriveIfLi20EE,"aG",@progbits,typeinfo for derive<float, 20>,comdat
    .align 4
    .type    typeinfo for derive<float, 20>, @object
    .size    typeinfo for derive<float, 20>, 12
typeinfo for derive<float, 20>:
    .long    vtable for __cxxabiv1::__si_class_type_info+8
///////////////////////tsecer注释开始///////////////////////
说明是一个si类型,single inheritance的类型,就是说单继承,如果是多继承,应该是mi吧。其实不是,是叫vmi表示virtual or multiple inheritance,这些细节估计没啥人关心,所以略过。接下来是一个名字的字符串,也就是typeid().name()返回的内容。再接下来是一个typeinfo for base的引用,这个对应gcc内码中的下面定义
 class __si_class_type_info : public __class_type_info
  {
  public:
    const __class_type_info* __base_type;这个结构是编译时动态生成的一个对象,它的内容在编译时已经确定,就是base结构的typeinfo地址
////////////////////////////////////////tsecer注释结束///////////////

    .long    typeinfo name for derive<float, 20>
    .long    typeinfo for base

    .weak    typeinfo name for base
    .section    .rodata._ZTS4base,"aG",@progbits,typeinfo name for base,comdat
    .type    typeinfo name for base, @object
    .size    typeinfo name for base, 6
typeinfo name for base:
    .string    "4base"
    .weak    typeinfo for base
    .section    .rodata._ZTI4base,"aG",@progbits,typeinfo for base,comdat
    .align 4
    .type    typeinfo for base, @object
    .size    typeinfo for base, 8
typeinfo for base:
    .long    vtable for __cxxabiv1::__class_type_info+8
    .long    typeinfo name for base
    .ident    "GCC: (GNU) 4.4.2 20091027 (Red Hat 4.4.2-7)"
    .section    .note.GNU-stack,"",@progbits
[root@Harry typename]#
有兴趣的同学可以看一下开始的typeid的反汇编代码,就是返回虚函数地址向上偏移一个int之后的地址,那就是typeinfo信息。
看一下typeinfo的name函数实现
  class type_info
  {
  public:
……
    const char* name() const
    { return __name; }
}
直接返回的就是自己的__name成员,也就是第二个成员(第一个是虚函数表地址)。
  评论这张
 
阅读(969)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017