C++编译并链接到指向未定义函数的指针
C++ compiles and links with pointer to undefined function
此代码:
void undefined_fcn();
void defined_fcn() {}
struct api_t {
void (*first)();
void (*second)();
};
api_t api = {undefined_fcn, defined_fcn};
定义全局变量api
,其中包含指向不存在函数的指针。然而,令我惊讶的是,它编译的链接绝对没有来自 GCC 的投诉,即使所有这些-Wall -Wextra -Werror -pedantic
标志也是如此。
此代码是共享库的一部分。只有当我在运行时加载库时,它才会最终失败。如何在库链接时检查我是否忘记定义任何函数?
更新:这个问题提到了同样的问题,答案是一样的:-Wl,--no-undefined
。(顺便说一句,我想这甚至可以标记为重复)。但是,根据下面接受的答案,使用时应小心-Wl,--no-undefined
.
此代码是共享库的一部分。
这才是关键。拥有共享库的全部目的是拥有一个"不完整"的共享对象,其中包含未定义的符号,当主可执行文件加载它以及与之链接的所有其他共享库时,必须解析这些符号。此时,运行时加载程序尝试解析所有未定义的符号;并且必须解析所有未定义的符号,否则可执行文件将无法启动。
你说你正在使用gcc
,所以你可能正在使用GNUld
。由于上述原因,ld
将使用未定义的符号链接共享库,但将无法链接可执行文件,除非针对可执行文件链接的共享库解析所有未定义的符号。因此,在运行时,预期的行为是运行时加载程序也应成功解析所有符号;因此,运行时加载程序无法启动可执行文件的唯一情况将指示致命的运行时环境故障(例如共享库被替换为不兼容的版本)。
有一些选项可用于覆盖此行为。--no-undefined
选项指示ld
在链接共享库时报告未定义符号的链接失败,就像可执行文件一样。当通过gcc
间接调用ld
时,这变得-Wl,--no-undefined
。
但是,您可能会发现这将是一个失败的命题。您最好希望共享库中的任何代码都不使用标准 C++ 或 C 库中的任何类。因为,你猜怎么着?-- 这些引用将是未定义的符号,您将无法链接您的共享库!
换句话说,这是你需要处理的必要邪恶。
你不能让编译器告诉你是否忘记在该实现文件中定义函数。 原因是当你定义一个函数时,它在C++中隐式标记为extern
。 而且在链接共享库之前,您无法判断共享库中的内容(编译器的链接器不知道是否定义了引用)
如果您不熟悉extern
的含义。 标记extern
的东西表示外部链接,因此,如果您有一个extern
变量,编译器不需要将该变量的定义放在使用它的翻译单元中。 定义可以位于另一个实现文件中,引用在链接时解析(当您与定义变量的翻译单元链接时)。 这同样适用于函数,函数本质上是函数类型的变量。
要获得您想要的行为,请创建函数static
,它告诉编译器该函数未extern
并且是当前翻译单元的一部分,在这种情况下,必须定义它-Wundefined-internal
接受此(-Wundefined-internal
是-Werror
的一部分,所以只需使用它进行编译)
- 从python调用openMP共享库时,未定义opnMP函数
- 具有外部"c"和程序集的未定义函数
- 已定义函数时出现 G++ "未定义的引用"错误
- 对显式实例化的模板函数的未定义引用
- 编译问题:在函数"_start"中:未定义对"主"的引用 collect2:错误:ld 返回 1 个退出状态
- 为什么我会收到警告,指出函数已使用但未定义,以及已定义但未使用?
- 2个模板化类的非模板友元函数未定义引用错误
- 使用内联函数 c++ 的未定义引用
- MacOS 上的 Xcode 11 项目不在一个函数中使用 sin 和 cos:未定义的符号"___sincosf_stret"
- 仅在 MacOS 上析构函数的未定义符号
- 如果用户尝试从 JS 调用对象的未定义函数C++则回调C++代码
- C++编译并链接到指向未定义函数的指针
- C++:定义函数时出现未定义函数错误
- 奇怪的未定义函数引用,函数调用C++不存在
- 类型为"double"的输入参数的未定义函数
- Android NDK:创建一个未定义函数的库
- c++ Builder调用未定义函数hypot/ceil/floor/fab
- 通过 GDB 设置断点时未定义函数"d::~d"
- 如何像传递未定义函数一样传递未定义方法
- 确定未定义函数的参数类型