C/C++代码中函数的多重定义
Multiple definition of a function in C/C++ code
这是一个关于C/C++函数定义的问题。所讨论的代码是静态库libRmath
,它在R
中的Rmath.h
头文件中提供定义。
为库提供的文档指出,用户可以选择为函数double unif_rand(void)
提供函数定义。
所以我的问题是,如果这样的函数定义是可选的,那么C/C++
中不允许有多个函数定义的问题吗?
编辑:在不看源代码的情况下推测事情是如何工作的可能很诱人,但这不是我想要的。我很想知道是如何真正工作的,所以你可能需要阅读源代码和文档来回答这个问题。
链接应用程序时,将使用您提供的库解析未解析的符号。如果你不定义一个函数,在链接过程中它将是一个未解析的符号,因此,在这种情况下,链接者将尝试使用librmath解析该符号。如果一个或多个符号无法解析,则会出现链接器错误。
但是,如果您确实在代码中定义了函数,那么它将在链接过程中已经定义,因此不需要使用外部库中的符号来解决它。
您不能在应用程序中多次定义同一个符号。
编辑:由于在另一个答案中有很多争论,我做了一个实际的例子。我创建了一个共享对象(类似于windows中的DLL),它定义并导出函数foo
:
//lib.h
extern "C" {
void foo();
void bar();
};
//lib.cpp
#include <iostream>
#include "lib.h"
void foo() {
std::cout << "From libn";
}
void bar() {
std::cout << "Bar, calling foon";
foo();
}
为了测试这个共享对象,我创建了一个与之链接的应用程序:
//test.cpp
#include <iostream>
#include "lib.h"
void foo() {
std::cout << "From appn";
}
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
函数(而不是共享对象)。基本上可以对共享对象中的每个导出符号执行此操作。
EDIT2:我在lib.h中添加了另一个导出的函数。应用程序现在调用这个函数,它最终调用foo。结果和预期的一样。
EDIT3:好的,让我们深入了解。这是来自函数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)
或者使用提供的(并且使用动态库或DLL必须使用提供的
文档明确指出,如果您使用动态库,则无法提供自己的unif_rand
实现。因此,我相信我所指出的,实际上回答了你的问题。
静态库中的定义只有在需要时才会被拉入,因此它们不会导致多个定义错误。
这有一些副作用,例如,当主程序中没有任何内容引用该对象时,静态库中的全局初始化程序不运行这一众所周知的问题。
- 在命名空间中定义函数还是限定函数
- 为什么在定义函数之前先声明它
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- 这个c++代码是如何在没有定义函数的情况下运行的
- 具有外部"c"和程序集的未定义函数
- 已定义函数时出现 G++ "未定义的引用"错误
- 将自定义函数传递到基抽象类中以延迟执行
- C++使用 rand 定义函数语法
- Arduino:在 loop() 和自定义函数中运行相同的代码时出现问题
- 将具有固定签名的自定义函数名称注入 CRTP
- 使用定义函数模板别名
- 是否可以使用单个定义定义函数的常量和常规版本?(使用模板,自动,decltype等)
- 在内联程序集中定义函数和从 C++ 调用时出现问题
- 在 Metal 着色器代码中,如何定义函数的 in/out 参数变量?
- 声明和定义函数静态会产生"undefined reference to function_name()"
- 朋友定义函数的名称空间是什么
- 介子 对用户定义函数的未定义引用
- 如何使用 "using" 关键字定义函数原型/签名
- 在 C 结构中定义C++函数