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

Fra*_*cci 2 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)
Run Code Online (Sandbox Code Playgroud)

我之前从未遇到过这样的事情,我在网上找到的大部分信息都涉及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;
}
Run Code Online (Sandbox Code Playgroud)

joh*_*boy 17

您有以下代码行:

int lookup (const struct entry dictionary[], const char search[], const int entries);
Run Code Online (Sandbox Code Playgroud)

里面的主要功能.这有两个主要问题.

  1. 函数声明不能​​出现在另一个函数内部.我引用的行需要出现在主函数之外,如下所示:

    int lookup(.....)
    //code here
    int main(...)
    {
        //more code here
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 即使您声明函数"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;
}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助.如果您不理解"链接器"的作用或为什么这很重要,请留下评论,我将相应地编辑我的答案.了解链接器和编译器是将平庸的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;
}
Run Code Online (Sandbox Code Playgroud)

如果我们查看这个玩具程序的机器代码,我们会看到每个函数在计算机内存中都有一个起点和一个终点.这意味着每个函数都有一个启动的地址.当您的计算机执行该行

int total = addnums(mynums, 5);
Run Code Online (Sandbox Code Playgroud)

它需要"跳转"到机器代码的不同部分."int main()"可能从地址100开始,"int addnums()"在地址50处.当计算机到达此行时,需要在地址50处执行机器代码.

编译器不关心函数的地址.它只是编译代码,并将其留给另一个程序将正确的地址放入机器代码中.如果链接器说的话

symbol(s) not found
Run Code Online (Sandbox Code Playgroud)

这意味着链接器不知道某个函数的地址.这通常是因为有问题的函数从未声明或定义过.如果链接器要从此代码生成可执行文件,则您的计算机将到达该行

int total = addnums(mynums, 5);
Run Code Online (Sandbox Code Playgroud)

并说"嗯???我该去哪儿?" 没有地址跳转到"int addnums()"函数,你的CPU将完全丢失.

而你的程序会神秘崩溃.

链接器通过删除错误并停止编译过程来节省您的心痛.在我编程嵌入式系统的业余时代,我曾经有过几次这个问题,这是调试的噩梦.

希望这可以帮助.告诉我,如果我的解释是坏的.

  • 我将编辑我的评论以解释链接器是什么.我希望它有道理:) (4认同)