基本支持函数重载的语言都需要进行name mangling。mangling的目的就是为了给重载的函数不同的签名,以避免调用时的二义性调用。C++程序员需要感谢GNU,GNU BinUtils的工具链用起来实在是太舒服了。
(1)先定义两个简单的函数:
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。
(2)可以看一个更复杂的例子,代码引自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。
(3)除了用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]()
注1:我在这里被坑了一次,我直接把上面nm产生的输出(__ZN9wikipedia7article6formatB5cxx11Ev)当作输入。 你把这个当作输入是错的,因为它有两个下划线。实际上应该是一个下划线。你怎么会想到nm产生的符号信息有误!!!!
注2:想接触C++多线程编程,需要从哪方面入手,有没有推荐的书籍或教程?
多线程编程的难点不在于锁,正常人看一下操作系统再写几个线程demo就可以基本理解了。对于C++而言,甚至连编写线程安全的类也不是难事。只需要用同步原语来保持对共享资源的访问即可。
我个人觉得最需要的就是实战,写Demo谁都会写。同步原语就那么几个,信号量,互斥量,条件变量等。但是怎么用呢?当你从点击星际争霸到和玩家匹配进行游戏,这当中程序是怎么运行的?事件驱动是怎么驱动的?
就目前来说,我遇到的困难不是线程的死锁,而是对并发模型的理解。Actor,Reactor模式等。这些东西不实战,个人空想理解起来会吃力。
我推荐 @陈硕老师的《Linux多线程服务端编程》,我最近在看这本书。这本书给我的观点是实战性很强,而且涉及面也比较广。后几章提到了分布式系统和作者对C++的思考以及STL algotrithm的运用。如作者所说:“对于面向对象,封装式必须的;但继承和多态耦合性太强,很不划算”我就很赞同。同时展示了一个用C++开发的网络库,不过虽然看了这本书,我还是没找到为什么要用C++的理由。我认为C的确可以很好地解决问题。C++的话就RAII算是真的有益处。