2011-04-29 46 views
0

大多数在UNIX上工作的人经常会面临这种令人烦恼的错误。 有时需要更少的时间来解决,有时会花费很多时间。未找到符号AKA未定义的符号

即使我经常遇到这样和我需要一些好的文件或关于c中的特定错误的文章/ C++

哪些地方有可能是找不到符号/未定义的符号错误的所有情况。

有人能帮我知道那些情况是什么吗?

+0

在什么情况下? – 2011-04-29 07:19:40

+0

编译时出现链接器错误 – Vijay 2011-04-29 09:11:17

回答

1

对于大多数情况下,当您找到符号未找到/未定义符号或有时甚至是“重复符号”错误时,它们通常源自链接程序无法在您尝试的项目中找到该符号的事实建立。

最好的方法是查看生成的映射文件或作为编译器输出的符号表。它可能是这个样子:

Symbols

这将让你看到如果符号存在或不存在。此外,还可能存在其他深奥的问题,例如编译器优化,可能会导致符号重复,特别是内联汇编。这些是最难以发现的。

至于良好的资源和材料,我没有很多很好的参考。当我问到那时,大多数高级工程师实际上已经从他们自己的经验中学到了东西。

但是我相信这样的论坛可以帮助我们加快获取知识。

希望它帮助:)

干杯!

+0

我很抱歉,但我一直在试图上传图片,以便获得示例视图,但无济于事。我确实选择了要上传的小jpg文件,但它一直被拒绝。我在某个地方出了问题吗? – Vern 2011-04-29 07:36:19

3

该错误与UNIX/Windows /任何其他操作系统无关,而与语言本身无关。使用编译器提供的信息进行诊断实际上很简单。通常他们会告诉你什么符号丢失了,有时候会在哪里使用。对于失踪的象征,主要理由是:

  • 您已经声明,但从未将它定义
  • 您已经定义它,但没有编译符号(目标文件/库)添加到链接
  • 它是外部的,您忘记链接库,或者您链接的是无效版本,或者顺序错误。

第一个是,如果你打算定义符号,但不匹配的声明(声​​明void foo(int, double);,但定义void foo(double, int)有点棘手。与所有其他情况下,编译器会告诉你确切的签名确保你已经定义了这个符号,而不是某个特定的或者类似的东西,如果你在声明和定义中使用了不同的调用约定,那么特定的角落案例可能会是,因为它们看起来非常相似在代码中。

在库外部代码的情况下,复杂性在于确定哪些库需要链接以便添加该符号,并且来自lib的文档。请注意,使用静态库时,链接器命令行中的库的顺序会影响结果。

为了帮助您找到实际定义的符号,您可以使用nm(gcc,这在UNIX系统中很常见)。所以基本上你可以运行nm针对你正在链接的目标文件/库,并搜索链接器正在抱怨的符号。这将有助于在顺序是造成差异的情况下(即符号在那里,但链接器跳过它)。在运行时(感谢Matthieu M.指出),如果在LD_LIBRARY_PATH中找到错误版本的库,那么您可能会遇到与动态库类似的问题,您最终可能会得到一个没有所需的符号。

+1

当然,微妙的问题是,你在链接时声明了一个依赖关系,但不幸的是'LD_LIBRARY_PATH'不像你所期望的那样,并且最终(在加载时)与不同版本的库链接,未定义您所期望的符号(例如,二进制兼容性问题)。 – 2011-04-29 08:48:48

+0

@Matthieu M.很好,我只是在编译时考虑。 – 2011-04-29 09:09:25

+0

我只使用DLLs,所以对我来说这是一个经常性问题:) – 2011-04-29 09:12:40

1

我假设你指的是链接器错误。以下列出了我认为最常见到最不常见的一个列表:

  • 您忘了告诉链接器有关依赖关系(例如LIB文件)的信息。
  • 你有一个静态数据成员的类,忘记初始化它(只有C++)。
  • 您声明的函数不是纯粹虚拟的,并且忘记实现它。
  • 你忘了实现一个你从另一个函数中调用的函数(只有C,C++会给出一个更容易找到的编译器错误)。
  • 您声明了一个外部变量并忘记初始化它。
  • 该函数的声明与实现不匹配(只有C++,C会接受它并可能死亡)。
  • 您忘记了实现您从另一个函数声明和调用的函数。
+0

如果你忘记实现一个函数,C++编译器就不会告诉你这个问题。它将满足函数声明。 – 2011-04-29 08:46:12

+0

@MatthieuM:嗯,有两个子弹处理这个(第四和最后)。两者之间的差异很小但很重要。在C中,你可以调用一个函数而不必先声明它。如果您未能定义(实现)它,链接器将会投诉。在C++中,如果没有编译器的抱怨,你不能使用未声明的函数。这是第4号子弹的意思。现在,如果你确实声明了它,但没有定义它,链接器会抱怨C和C++。这是最后一颗子弹的意思。 – 2011-12-10 22:05:27

2

虽然他们可以依赖于平台,我有一些来自安德烈亚斯和大卫点的一些“更加复杂”实例:

  • 当共享库(.so or.dll)和处理链接到未导出的符号(Windows上的dllimport/dllexport以及* nix上的GCC的可见性(“默认”))
  • 或类似:链接静态库,期望共享库,反之亦然。这与Mathieu关于链接另一个意外版本库的评论有些相似。
  • 创建一个纯虚拟类,并且不为至少一个方法提供实现(不会导致vtable可用)。
  • 实际上是一个更复杂的声明但未定义的情况:处理大型嵌套模板时可能会遇到链接错误。查找大量错误消息可能很难找出未定义的内容。