C++ 代码中对 C 函数的未定义引用

undefined reference to c functions in c++ code

我有一个奇怪的问题:下面的代码完美编译。
src.cpp:

extern "C" {
    #include "header.h"
}

void A::Execute() {
    B::Instance().Reset(ix);
    c_func(ix);// this is c functions declared in header.h
    C::Instance().Erase(ix);
}

但是当我注释掉 c_funk() 时,我在所有使用 header.h 文件中的 c 函数的地方都出现了链接错误。

有了这个小改动:

void A::Execute() {
    B::Instance().Reset(ix);
    //c_func(ix);// this is c function declared in header.h
    C::Instance().Erase(ix);
}

我得到:对 c_func() 的未定义引用。
任何想法如何解决它?谢谢

更新:
我在 header.h 中添加了一个虚拟函数:foo_for_linkage_problem();
并以这种方式解决了问题。据我了解,链接器会尝试进行一些优化来解决此问题。新代码:

void A::Execute() {
    B::Instance().Reset(ix);
    foo_for_linkage_problem();// this is c empty function declared in header.h 
    C::Instance().Erase(ix);
}

tldnr:您在向 linker 提供库的顺序上遇到问题。

我想我知道哪里出了问题。假设您有四个文件:

main.c:

#include <stdio.h>
    
int a();
int b();

int main()
{
    printf("%d\n", a());
    printf("%d\n", b());

    return 0;
}

main2.c:

#include <stdio.h>
    
int a();
int b();

int main()
{
    //printf("%d\n", a());
    printf("%d\n", b());

    return 0;
}

a.c:

int a()
{
    return 67;
}

b.c:

int a();

int b()
{
    return a()+5;
}

我们创建 liba.alibb.a:

gcc a.c -c -o a.o
gcc b.c -c -o b.o
ar rcs liba.a a.o
ar rcs libb.a b.o

现在我们编译我们的exec:

gcc main.c liba.a libb.a -o test

一切正常

gcc main2.c liba.a libb.a -o test

我得到:

libb.a(b.o): In function `b':
b.c:(.text+0xa): undefined reference to `a'
collect2: error: ld returned 1 exit status

让我们检查一下我的库中有哪些符号 provides/requires:

$nm liba.a

a.o:
0000000000000000 T a

符号类型T表示这个库有文件a.o提供符号a

$nm libb.a

b.o:
                 U a
0000000000000000 T b

libb.a 包含提供符号 b 但需要符号 a

的文件 b.o

linker 在被询问时不包括整个静态库。它看起来需要 .o 个文件,而只需要 link 个文件。因此,您提供文件的顺序至关重要。

当执行以下命令时,main.c 被编译并且它需要 ab 符号。当 linker 获取 liba.a 库时,它 links a.o 文件,因为它提供 a 符号。当 linker 获得 libb.a 库时,它 links b.o 文件,因为它提供 b 符号。一切正常。

gcc main.c liba.a libb.a -o test

当执行 main2 命令时,main2.c 被编译,它只需要 b 个符号。当 linker 获得 liba.a 时,它不会 link a.o 因为根本不需要 a。然后 linker 获取 libb.a 库它 links b.o 文件因为它提供 b 符号。但是b.o文件需要符号a,来不及linka.oliba.a已经处理了。请注意,当 我切换库它会干净地编译:

gcc main2.c libb.a liba.a -o test