連結時未定義的引用錯誤
編譯中最常見的錯誤之一發生在連結階段。該錯誤看起來類似於:
$ 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(int foo();
) 的宣告,但沒有它的定義 (實際函式)。所以我們為編譯器提供了函式頭,但是在任何地方都沒有定義這樣的函式,所以編譯階段通過但連結器以 Undefined reference
錯誤退出。
要在我們的小程式中修復此錯誤,我們只需要為 foo 新增一個定義 :
/* 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;
}
現在這段程式碼將編譯。另一種情況出現在 foo()
的源位於一個單獨的原始檔 foo.c
中(並且有一個標頭檔案 foo.h
來宣告 foo()
包含在 foo.c
和 undefined_reference.c
中)。然後修復是連結 foo.c
和 undefined_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()
的宣告存在於 #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()
的定義。要解決這個問題,我們必須通過指定 -lm
標誌來指定我們想要連結到名為 libm
的數學庫。 (請注意,有些平臺,如 macOS,不需要 -lm
,但是當你得到未定義的引用時,需要庫。)
所以我們再次執行編譯階段,這次指定庫(在原始檔或目標檔案之後):
$ 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
$
它的工作原理!