nm命令输出中的奇怪符号名称

10
我建立了一个名为InterfaceLayer.so的动态库。 当我调用它时:
> nm InterfaceLayer

作为输出,我得到了一些看起来像这样的符号:
00000e28  T _Z5startv

在我的代码中,我期待它是“start”,因为这正好是我定义的函数名称。
为什么会出现这种情况?
3个回答

22

这是因为 C++ 进行名称修饰所致。

nm -C

消除名称修饰。

为了防止名称修饰,

  • 使用C编译器(gcc,而不是g ++),将源文件命名为.c(而不是.cpp)
  • 或声明extern "C":

.

my.h

  extern "C" 
  {
        void start();
        void finish();
  }

这将为它们提供"C"链接,这意味着它们不能被重载,不能通过引用传递,没有C++的什么功能 :)


“extern C”并不意味着函数不能通过引用传递。 - AnT stands with Russia
2
建议从C++切换到C“以防止名称混淆”听起来像是建议使用断头台来预防头皮屑。顺便说一句,原帖作者从未表示他们想要预防它。 - AnT stands with Russia
2
同意。解释C++是名称修饰的来源可能会增加一些视角。“为什么会发生这种情况”在问题中是明确提出的。 - sehe

3

3
我经常在需要反混淆时使用c++filtc++filt _Z5startv - karlphillip
1
nm myApp | c++filt; # 这正是我所需要的。我在OSX和XCode上使用它扭曲的GNU工具栈,它不支持nm -C。感谢@karlphillip - matiu

2

正如其他答案所提到的,这很可能是由于C++名称重载导致的。如果你想让该符号通过其“未重载”的名称访问,并且它是用C++实现的,则需要使用extern "C"告诉C++编译器它具有C语言链接。

在具有函数原型的头文件中,您需要像下面这样的内容:

#if defined(__cplusplus)
extern "C" {
#endif

// the prototype for start()...


#if defined(__cplusplus)
}
#endif

这会确保如果函数被C++编译器使用,它将在声明中得到extern "C",如果它被C模块使用,它不会被extern "C"说明符所迷惑。

如果你在函数定义之前包含头文件,则在.cpp文件中的实现不需要那些东西。它将使用从先前声明中看到的链接规范。然而,我仍然喜欢用extern "C"修饰函数定义,以确保一切同步(请注意,在.cpp文件中,您不需要#ifdef预处理部分 - 它将始终被编译为C ++)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接