C: 链接器命令失败,退出代码为 1

标签 c linker

我在编译代码时遇到问题。我没有收到任何错误消息。但是,我收到以下消息:

Undefined symbols for architecture x86_64:
  "_lookup", referenced from:
      _main in sixteen2-85c27c.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我以前从未遇到过这样的事情,我可以在网上找到的大部分信息都涉及 Objective-C,而不是普通的 C。我将不胜感激。

这是我的代码:
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    struct entry {
        char word[15];
        char definition[100];
    };

    const struct entry dictionary[100] = 
    {{"aardvark", "a burrowing African mammal"},
    {"abyss", "a bottomless pit"},
    {"acumen", "mentally sharp; keen"},
    {"addle", "to become confused"},
    {"aerie", "a high nest"},
    {"affix", "to append; attach"},
    {"agar", "a jelly made from seaweed"},
    {"ahoy", "a nautical call of greeting"},
    {"aigrette", "an ornamental cluster of feathers"},
    {"ajar", "partially opened"}};

    int entries = 10;
    int entryNumber;
    int lookup (const struct entry dictionary[], const char search[], const int entries);

    if (argc != 2)
    {
        fprintf (stderr, "No word typed on the command line.\n");
        return EXIT_FAILURE;
    }

    entryNumber = lookup (dictionary, argv[1], entries);

    if (entryNumber != -1)
        printf("%s\n", dictionary[entryNumber].definition);
    else
        printf("Sorry, %s is not in my dictionary.\n", argv[1]);

    return EXIT_SUCCESS;
}

最佳答案

您有以下代码行:

int lookup (const struct entry dictionary[], const char search[], const int entries);
在主函数里面。这有两个主要问题。
  • 函数声明不能​​出现在另一个函数内部。我引用的行需要出现在您的主要功能之外,如下所示:
    int lookup(.....)
    //code here
    int main(...)
    {
        //more code here
    }
    
  • 即使你声明了函数“lookup”,你也永远不会定义 它。这可能是导致链接器错误的原因。编译器编译所有的函数,然后链接器去将这些函数链接在一起(可以这么说)并发现,虽然函数“lookup”被声明然后被调用,但它实际上并不存在于任何地方! (据我所知,stdlib.h 或 stdio.h 中不存在函数“lookup”)。这会阻止链接器完成其工作。

  • 总结一下,您的代码应重新组织如下:
    #include <stdio.h>
    #include <stdlib.h>
    
    int lookup (const struct entry dictionary[], const char search[], const int entries)
    {
        //lots of code belongs in here, but that's for you to figure out :)
    }
    
    int main (int argc, char *argv[]) {
        struct entry {
            char word[15];
            char definition[100];
        };
    
        const struct entry dictionary[100] = 
        {{"aardvark", "a burrowing African mammal"},
        {"abyss", "a bottomless pit"},
        {"acumen", "mentally sharp; keen"},
        {"addle", "to become confused"},
        {"aerie", "a high nest"},
        {"affix", "to append; attach"},
        {"agar", "a jelly made from seaweed"},
        {"ahoy", "a nautical call of greeting"},
        {"aigrette", "an ornamental cluster of feathers"},
        {"ajar", "partially opened"}};
    
        int entries = 10;
        int entryNumber;
        //**REMOVE THIS LINE**  Move it up top....
        //int lookup (const struct entry dictionary[], const char search[], const int entries);
    
        if (argc != 2)
        {
            fprintf (stderr, "No word typed on the command line.\n");
            return EXIT_FAILURE;
        }
    
        entryNumber = lookup (dictionary, argv[1], entries);
    
        if (entryNumber != -1)
            printf("%s\n", dictionary[entryNumber].definition);
        else
            printf("Sorry, %s is not in my dictionary.\n", argv[1]);
    
        return EXIT_SUCCESS;
    }
    
    我希望这有帮助。如果您不明白“链接器”的作用或为什么这很重要,请发表评论,我将相应地编辑我的答案。理解链接器和编译器是区分普通 C 程序员和优秀 C 程序员的众多因素之一!

    我认为在这一点上解释链接器是有用的。但是,在我们开始之前,了解编译器的作用以及编译后的程序究竟是什么很重要。
    根据您在问题中发布的代码,我认为可以安全地假设您多次使用编译器:)。我要说一些你已经知道的事情,但请坚持下去。您所拥有的“.c”和“.h”文件描述了算法。这些文件易于人类阅读和编辑,但是,您的计算机可能很难从中提取含义。为了让您的计算机“运行”这些文件中的程序,需要将算法转换为您的计算机可以理解的语言。这种被称为“机器语言”的语言对于人类来说很难编写,所以我们用 C 或 C++ 编写,并使用编译器将我们的 C 和 C++ 程序转换为“机器语言”。
    现在,这里链接器的功能是微妙但非常重要的。初学者很容易认为链接器完全没有必要:如果编译器将 C 转换为“机器语言”,那么工作就结束了,对吧?嗯……不完全是。
    你看,你编译的程序中的每一点“机器语言”都有一个内存地址。考虑以下玩具示例:
    #include <stdio.h>
    
    int addnums(int numbers[], int length)
    {
        int total = 0;
        for(int i = 0; i < length; i++)
        {
            total += numbers[i];
        }
        
        return total;
    }
    
    int main(int argc, char** argv)
    {
        int mynums[] = {1, 2, 3, 4, 5};
        int total = addnums(mynums, 5);
        printf("the total of the array is %i\n", total);
        return 0;
    }
    
    如果我们查看这个玩具程序的机器代码,我们会看到每个函数在您的计算机内存中都有一个起点和一个终点。这意味着每个函数都有一个 地址 它开始的地方。当您的计算机执行该行时
    int total = addnums(mynums, 5);
    
    它需要“跳转”到机器代码的不同部分。 “int main()”可能从地址100开始,而“int addnums()”在地址50。当你的计算机到达这一行时,你的计算机需要执行地址50的机器代码。
    编译器不关心函数的地址。它只是编译代码,然后让另一个程序将正确的地址放入机器代码中。如果链接器说类似的话
    symbol(s) not found
    
    这意味着链接器不知道某个函数的地址。这通常是因为所讨论的函数从未被声明或定义过。如果链接器要从此代码生成可执行文件,则您的计算机将到达该行
    int total = addnums(mynums, 5);
    
    然后说“嗯?我要去哪里??”如果没有跳转到“int addnums()”函数的地址,您的 CPU 将完全丢失。

    你的程序会神秘地崩溃。
    链接器通过删除错误并停止编译过程来为您省去这个心痛。在我业余编程嵌入式系统的日子里,我遇到过几次这个问题,调试是一场噩梦。
    希望这可以帮助。如果我的解释不好,请告诉我。

    关于C: 链接器命令失败,退出代码为 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30697987/

    相关文章:

    c - 在 C 中调用函数时出现预期表达式错误

    c++ - 链接到某物是什么意思?

    macos - Clang 代码覆盖率 - Mac OS X - 链接器错误

    linker - 了解 .cbproj 文件中的包导入

    c++ - "decode"Visual Studio 链接错误怎么办?

    c - 制作更高效的功能——字数计数器

    c - 这个二进制转十进制的程序是否正确?

    c - 为什么有人会使用 gboolean (GLib) 而不是 bool 类型?

    c - 我如何让我的程序读入 value=judges

    c++ - 使用多个命名空间对 vtable 的 undefined reference