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 
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<std::endl;
  if(demangle_name==NULL)
    std::cout<<"demangle failued."<<std::endl;
  std::cout<std::endl;
  free(demangle_name);
  return 0;
}

输出如下:

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

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

__ZN9wikipedia7article6formatB5cxx11Ev

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

你可能感兴趣的:(C/C++)