【问题标题】:How do I rectify inconsistent Unresolved External errors? [duplicate]如何纠正不一致的未解决的外部错误? [复制]
【发布时间】:2013-04-06 19:37:05
【问题描述】:

我正在尝试使用 SFML 库进行 C++ 开发。我正在学习教程 (http://www.gamefromscratch.com/page/Game-From-Scratch-CPP-Edition-Part-7.aspx),并使用 Visual Studio 2010。

我一直遇到的关于未解决的外部问题的问题。我真的在为此苦苦挣扎,因为与我遇到的大多数错误不同,它似乎 a) 与代码没有任何关系,并且 b) 行为不一致。与其给你们一个具体的例子并寻求帮助来解决这个例子,我希望开发一种更可靠的方法来解决这些问题。不过,我会给你一个常见情况的概要。

我有一个解决方案,有 8 个头文件和 8 个对应的 cpp 文件。解决方案是稳定的:它编译和运行没有错误或警告。

我将进入一个头文件并添加这一行:

虚空DoNothing();

然后我会进入匹配的cpp文件并编写方法:

void DoNothing(){};

我编译并运行,得到 5 个未解决的外部错误。它们没有指向任何代码行,所以我真的不知道如何修复它们,但我显然做错了什么。很公平。为了回到稳定状态,我删除了我插入的两行代码,然后编译。即使代码与最后一个稳定状态相同,我也会得到相同的未解决的外部错误。

尝试随机的东西,我进入另一个 cpp 文件并颠倒两个包含的头文件的顺序。游戏现在编译。如果我将包含的头文件的顺序切换回来,它就会编译。

什么是未解决的外部错误?为什么他们的行为似乎与我输入的代码不一致?我如何阅读它们以找出问题所在,以及如何首先避免它们?

谢谢。

ps:如果我应该提供更具体的细节,请告诉我。

【问题讨论】:

  • 在您的示例中,您似乎没有限定名称。应该是void SomeClass::DoNothing(){}
  • 请提供SSCCE

标签: c++ visual-studio debugging sfml unresolved-external


【解决方案1】:

每次我看到这样的行为都是因为项目之间的循环引用。例如,项目 A 引用了项目 B 中实现的对象/符号,同时项目 B 引用了项目 A 中的对象/符号。每次构建解决方案时,工具都必须编译一个项目首先,然后是另一个。如果您对要编译的第二个项目进行更改,则第一个项目在第一轮编译中看不到更改,并且构建失败。如果您设法手动构建项目 B(针对现在已过时的库 B 副本),则解决方案开始正确构建。更复杂的循环是可能的(例如,A 依赖于 B,B 依赖于 C,而 C 又依赖于 A)。您没有明确提及多个项目,但我敢打赌您拥有它们。

这些循环引用在大型解决方案中很常见,这些解决方案已经存在了很长时间并且随着时间的推移增长缓慢。人们习惯于添加从所有事物到所有事物的链接,因为他们需要一个来自 here 的函数,一个来自 there 的结构......

找出这些依赖项。您应该能够从源代码进行完全干净的重建。你的依赖树应该看起来像……嗯,一棵树;不是图表。

【讨论】:

    【解决方案2】:

    “未解决的外部”错误意味着您的代码引用了不存在的东西(通常是函数或方法,但也可以是变量)。这些是 link 错误,而不是 compile 错误;这就是为什么您没有得到行号和更多有用的错误消息的原因。

    让我给你一些关于如何将 C++ 代码转换为可执行文件的背景知识(请记住,我正在简化一些事情。)

    项目中的每个 C++ 源文件(而不是头文件)都是单独编译的。 “.cpp”文件及其包含的所有头文件都被编译成所谓的目标文件目标代码。 (这些文件具有“.obj”或“.o”扩展名。)您还可以将库文件(即 Windows 上的“.lib”文件和 Linux 上的“.a”文件)视为这些目标文件的集合, 保存以备后用。

    为了生成可执行程序(例如 Windows 上的 EXE 或 DLL 文件),所有这些目标文件链接在一起

    现在,重要的是每个源文件都是独立编译的,并且独立于其他源文件。因此,如果一个文件中的代码调用了在另一个文件中实现的函数,编译器将看不到该函数的实际主体,并且只能假设只要被调用的 声明函数是可见的(即原型,即您在标题中编写的行),那么这些文件最终将被链接在一起,并将离开实际调用链接器的任务。这通常意味着只要您包含正确的标头,您的编译器就会很高兴。

    但是链接器会更加顽固和迂腐。在链接时,您确实需要提供您在整个项目中使用的所有功能的主体(即实现)。你的任务是确保所有正确的目标文件和库都链接在一起,并且每个使用的函数的实现在它们之间的某个地方恰好存在一次(不多也不少。)

    这给我们带来了您的问题。当您收到“未解决的外部”链接器错误时,这意味着您调用的函数的主体在您链接在一起的目标文件和库中的任何位置都不存在。

    显然,正在发生两件事之一。要么你已经包含了一个外部库的头文件,但是忘记了链接库文件本身(这不是你的问题)或者你已经声明了一个函数(即为它编写了原型)但忘记了实现它的主体.

    请记住,这里的链接器非常严格。如果你在课堂上声明这样的内容:

    class Foo {
        void bar (int x);
    };
    

    然后在你的“.cpp”文件中,实现这个函数:

    void bar (int x)
    {
        // Do nothing
    }
    

    如果你在程序中的任何地方实际调用Foo::bar(),那么你会得到一个未解决的外部错误,因为实现的bar()不是Foo的方法(你应该实现void Foo::bar (int x) {}。)类似的事情如果您拼写错误或参数类型错误或诸如此类,就会发生这种情况。

    阅读链接器错误并从中理解可能很困难。有时,链接器抱怨的名称(它说它找不到的“符号”)都被破坏得面目全非。这与 *Application Binary Interface*s (ABI) 和几十年的历史和优先级有关。无论如何,大多数时候,如果您仔细查看链接错误消息,您可以看到函数名称并检查您的代码(或库)并重试。

    此外,虽然这种情况很少见,但有时为了解决某些链接问题,您必须求助于完全重建您的项目。

    【讨论】:

      猜你喜欢
      • 2010-10-25
      • 1970-01-01
      • 2012-06-03
      • 2012-03-16
      • 2015-01-11
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      相关资源
      最近更新 更多