C++中的name mangling

我在这里先推荐一下陈硕的那本Linux多线程服务端编程,至于推荐这本书的原因,可以参见我在知乎上的回答。传送门
作者在C++编译链接模型精要章节中提到了name mangling。基本支持函数重载的语言都需要进行name mangling。mangling的目的就是为了给重载的函数不同的签名,以避免调用时的二义性调用。C++程序员需要感谢GNU,GNU BinUtils的工具链用起来实在是太舒服了。网上也有不少介绍name mangling的文章,不过貌似大多数都是抄的。反正我搜到的几篇都是一样的内容,字都懒得改改。

先定义两个简单的函数

double sum(double x,double y){ 
    return double();
}   

void foo(int lhs,int rhs){
}
g++ -c mangling.cc -o mangling.o
nm -a mangling.o

输出如下(我省略了部分内容):

00000022 T __Z3fooii
00000000 T __Z3sumdd

被修饰过的名字都以_Z开头,后面数字3是什么意思呢?3是指你的函数名长度。不信你可以换一个函数名试试。对于函数foo而言,ii的含义是你的参数类型的简写。ii代表int int
可以看一个更复杂的例子,代码引自wiki

#include <iostream>
namespace wikipedia
{
   class article
   {
   public:
      std::string format (void){
      }
      bool print_to (std::ostream&){
       }
      class wikilink
      {
      public:
         wikilink (std::string const& name){ }
      };
   };
}

这次部分输出如下:

__ZN9wikipedia7article6formatB5cxx11Ev

可以看出几乎是没有变化的,只不过前面多了该函数所在的命名空间和类。最后会跟一个大写字母E。PS:这个是约定。我个人猜测是End的意思吧。v的意思就很明确了,是指参数为void。5应该是指后面的cxx11
除了用nm看,还可以用abi::__cxa_demangle函数来实现run-time demangle。这个函数在调试的时候或许会有用,你想看那个函数被调用了。
可以写个简单的demo

int main(int argc,char **argv){
  const char *mangling_name="_ZN9wikipedia7article6formatB5cxx11Ev";
  char *demangle_name=(char*)malloc(30);
  int status = 0;
  std::size_t len=30;
  demangle_name=abi::__cxa_demangle(mangling_name,NULL,NULL,&status);
  std::cout<<status<<std::endl;
  if(demangle_name==NULL)
    std::cout<<"demangle failued."<<std::endl;
  std::cout<<demangle_name<<std::endl;
  free(demangle_name);
  return 0;
}

输出如下:

wikipedia::article::format[abi:cxx11]()

不过我在这里被坑了一次,我直接把上面nm产生的输出当作输入。

__ZN9wikipedia7article6formatB5cxx11Ev

你把这个当作输入是错的,因为它有两个下划线。实际上应该是一个下划线。你怎么会想到nm产生的符号信息有误!!!!
参考资料主要来自wiki和gnu
name mangling
__cxa_demangle
下面是坑的传送门
坑坑坑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值