但是,如果您在代码中定义了该函数,它将在链接期间已经定义,因此不需要使用外部库的符号来解析它。
您不能在应用程序中定义相同的符号超过一次。
编辑:由于另一个答案中有很多争论,我做了一个实际的例子。我创建了一个共享对象(类似于Windows的DLL),其中定义并导出了一个名为foo
的函数:
//lib.h
extern "C" {
void foo();
void bar();
};
//lib.cpp
#include <iostream>
#include "lib.h"
void foo() {
std::cout << "From lib\n";
}
void bar() {
std::cout << "Bar, calling foo\n";
foo();
}
为了测试这个共享对象,我创建了一个与它链接的应用程序://test.cpp
#include <iostream>
#include "lib.h"
void foo() {
std::cout << "From app\n";
}
int main() {
bar();
}
我已经编译了共享对象和应用程序:
g++ lib.cpp -o libtest.so -Wall -fPIC -shared -Wl,--export-dynamic -Wl,-soname,libtest.so -Wl,-z,defs
g++ test.cpp -o test -L. -ltest
当我执行test
,将库路径设置为"."
,以便可以加载我的共享对象时,我会得到如下输出:
matias@master:/tmp$ LD_LIBRARY_PATH="." ./test
Bar, calling foo
From app
正如您所看到的,应用程序中定义的foo
函数被调用(而不是共享对象)。您基本上可以为共享对象中的每个导出符号执行此操作。
编辑2:我已在lib.h中添加了另一个导出的函数。 现在应用程序调用此函数,该函数最终调用foo。 结果与预期相同。
编辑3:好的,让我们深入探讨。 这是bar
函数的转储:
Dump of assembler code for function bar@plt:
0x0804855c <+0>: jmp DWORD PTR ds:0x804a004
0x08048562 <+6>: push 0x8
0x08048567 <+11>: jmp 0x804853c
如果我们访问地址0x804a004
:
Dump of assembler code for function _GLOBAL_OFFSET_TABLE_:
0x08049ff4 <+0>: or BYTE PTR [edi+0x804],bl
0x08049ffa <+6>: add BYTE PTR [eax],al
0x08049ffc <+8>: add BYTE PTR [eax],al
0x08049ffe <+10>: add BYTE PTR [eax],al
.....
正如你所看到的,它正在跳转到全局偏移表。你可以在这里和这里了解有关GOT的信息。动态符号(在运行时解析的符号)存储在该表中。每当调用应在运行时解析的符号时,实际上会跳转到此表,然后跳转到存储在该表相应条目中的地址。由于应用程序定义了foo
,因此GOT包含来自test.cpp
中定义的地址,而不是我们共享对象中的地址。
EDIT4:好吧,最后一次编辑。引用文档:
您将需要提供均匀随机数生成器。
double unif_rand(void)
文档明确指出,如果您正在使用动态库,您不能提供自己的
unif_rand
实现。因此,我相信我所指出的实际上回答了您的问题。
foo
被调用了吗?而不是来自 DLL 的那个?顺便说一下,我很惊讶看到这个;我认为你做错了什么。无论如何,你会如何从 DLL 中调用 foo
? - Nawaz