C语言链接时存在未定义的参考错误

示例

编译中最常见的错误之一发生在链接阶段。该错误看起来与此类似:

$ gcc undefined_reference.c 
/tmp/ccoXhwF0.o: In function `main':
undefined_reference.c:(.text+0x15): undefined reference to `foo'
collect2: error: ld returned 1 exit status
$

因此,让我们看一下生成此错误的代码:

int foo(void);

int main(int argc, char **argv)
{
    int foo_val;
    foo_val = foo();
    return foo_val;
}

我们在这里看到了foo()的声明,但没有定义(实际函数)。因此,我们为编译器提供了函数头,但是在任何地方都没有定义此类函数,因此编译阶段通过了,但链接器退出并出现错误。要在我们的小程序中修复此错误,我们只需为foo添加一个定义:int foo();Undefined reference

/* Declaration of foo */
int foo(void);

/* Definition of foo */
int foo(void)
{
    return 5;
}

int main(int argc, char **argv)
{
    int foo_val;
    foo_val = foo();
    return foo_val;
}

现在,此代码将编译。另一种情况是,for的源foo()位于单独的源文件中foo.c(并且在和中都包含一个标头foo.h声明)。然后,解决方法是从和链接两个目标文件,或编译两个源文件:foo()foo.cundefined_reference.cfoo.cundefined_reference.c

$ gcc -c undefined_reference.c 
$ gcc -c foo.c
$ gcc -o working_program undefined_reference.o foo.o
$

要么:

$ gcc -o working_program undefined_reference.c foo.c
$

更复杂的情况是涉及库,如代码中所示:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(int argc, char **argv)
{
    double first;
    double second;
    double power;

    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <denom> <nom>\n", argv[0]);
        return EXIT_FAILURE;
    }

    /* Translate user input to numbers, extra error checking
     * should be done here. */
    first = strtod(argv[1], NULL);
    second = strtod(argv[2], NULL);

    /* Use function pow() from libm - this will cause a linkage 
     * error unless this code is compiled against libm! */
    power = pow(first, second);

    printf("%f to the power of %f = %f\n", first, second, power);

    return EXIT_SUCCESS;
}

该代码在语法上是正确的,声明为pow()from的存在#include <math.h>,因此我们尝试进行编译和链接,但会收到如下错误:

$ gcc no_library_in_link.c -o no_library_in_link
/tmp/ccduQQqA.o: In function `main':
no_library_in_link.c:(.text+0x8b): undefined reference to `pow'
collect2: error: ld returned 1 exit status
$

这是因为定义为pow()在链接阶段没有被发现。为了解决这个问题,我们必须指定我们要链接到libm通过指定-lm标志调用的数学库。(请注意,-lm不需要使用诸如macOS之类的平台,但是当您获得未定义的引用时,就需要该库。)

因此,我们再次运行编译阶段,这次指定了库(在源文件或目标文件之后):

$ gcc no_library_in_link.c -lm -o library_in_link_cmd
$ ./library_in_link_cmd 2 4
2.000000 to the power of 4.000000 = 16.000000
$

而且有效!