【问题标题】:Can GCC not complain about undefined references?GCC 不能抱怨未定义的引用吗?
【发布时间】:2011-07-30 03:55:31
【问题描述】:

在什么情况下,GCC 可能在尝试调用虚构函数时不抛出“未定义的引用”链接错误消息?

例如,这段C代码被GCC编译链接的情况:

void function()
{
    made_up_function_name();
    return;
}

...即使made_up_function_name 不存在于代码中任何地方(不是头文件、源文件、声明或任何第三方库)。

这种代码可以在一定条件下被 GCC 接受和编译,而不接触实际代码吗?如果有,是哪个?

谢谢。

编辑:在其他任何地方都没有以前对made_up_function_name 的声明或提及。这意味着整个文件系统的 grep -R 将仅显示确切的单行代码。

【问题讨论】:

  • 可以(只要您编译的是 C,而不是 C++)。你想完成什么?
  • 我不想完成任何事情,它已经在发生,我想知道为什么它是可能的。如果我使用“-g”并使用文本编辑器编辑文件,made_up_function_name 实际上存在于最终的链接二进制文件中。
  • 所有建议的答案都需要至少定义函数,即使原型是可选的。 “made_up_function_name”未在任何地方定义或原型化。
  • 阻止它成功链接,但不能编译。

标签: c gcc compiler-errors compiler-warnings


【解决方案1】:

是的,可以避免报告未定义的引用 - 使用 --unresolved-symbols 链接器选项。

g++ mm.cpp -Wl,--unresolved-symbols=ignore-in-object-files

来自man ld

--unresolved-symbols=method

确定如何处理未解析的符号。有四个 方法的可能值:

       ignore-all
           Do not report any unresolved symbols.

       report-all
           Report all unresolved symbols.  This is the default.

       ignore-in-object-files
           Report unresolved symbols that are contained in shared
           libraries, but ignore them if they come from regular object
           files.

       ignore-in-shared-libs
           Report unresolved symbols that come from regular object
           files, but ignore them if they come from shared libraries.  This
           can be useful when creating a dynamic binary and it is known
           that all the shared libraries that it should be referencing
           are included on the linker's command line.

共享库本身的行为也可以是 由 --[no-]allow-shlib-undefined 选项控制。

通常链接器会为每个 报告未解析的符号,但选项 --warn-unresolved-symbols 可以 将其更改为警告。

【讨论】:

  • clang 的等价物是什么?
【解决方案2】:

TL;DR它不能抱怨,但你不想要那样。如果您强制链接器忽略该问题,您的代码将会崩溃。会适得其反。

您的代码依赖于古老的 C(C99 之前),允许在使用时隐式声明函数。您的代码与以下代码在语义上等价:

void function()
{
    int made_up_function_name(...); // The implicit declaration

    made_up_function_name(); // Call the function
    return;
}

链接器正确地抱怨包含已编译的function() 的目标文件引用了在其他任何地方都找不到的符号。您必须通过为made_up_function_name() 提供实现或删除无意义的调用来修复它。这就是它的全部。不涉及链接器。

【讨论】:

  • 如果创建一个共享库,这是有道理的。
  • 这根本没有意义:您希望导入的符号不是未定义的,它们只是动态绑定的。我非常怀疑您是否真的尝试过它并且可以提供一些真实的场景 - 想想一系列 bash 命令创建源、编译和链接它们、转储二进制文件并演示那些 undefined-at-link-time符号。
  • 让我们文明一点。所以:我们有可以协同工作的库:比如 SDL2,以及附加库 SDL2_ttf、SDL2_image 和 SDL2_mixer。每个附加组件都需要在 SDL2 中链接吗?那不是给一个链接所有 4 个库的程序,SDL2 中函数的 4 个副本吗?
  • 完全没有,无论库是静态链接还是动态链接到生成的可执行文件,它都不会获得多个副本,唯一的限制是如果加载项动态链接到 SDL2,但是SDL2 没有动态链接到可执行文件,因此可执行文件本身需要导出 SDL2 的符号。这在 PE 和 ELF 中都是可能的,虽然它可能不是很流行,但它有有效的用例。假设您正在包装 Python 并希望静态链接它,但仍希望用户能够将自己的 Python C 模块添加到您的应用程序中。
  • 需要注意的是,如果 SDL2_foo 是共享模块并静态链接到 SDL2,那么每个模块都会携带自己的 SDL2 副本,我们当然不希望这样。
【解决方案3】:

如果你在使用它之前声明了函数的原型,它应该编译。无论如何,链接时的错误仍然存​​在。

void made_up_function_name();
void function()
{
    made_up_function_name();
    return;
}

【讨论】:

  • 已编辑问题以反映这一点:除了示例中显示的调用行之外,绝对没有其他提及组成的功能。
【解决方案4】:

然后,将 -D 标志传递给 GCC 会带来麻烦。

$cat undefined.c
void function()
{
    made_up_function_name();
    return;
}


int main(){
}

$gcc undefined.c -Dmade_up_function_name=atexit
$

想象一下寻找made_up_function_name的定义——它在代码中还没有出现“做事”。 我想不出在代码中做这件事的好理由。

-D 标志是在编译时更改代码的强大工具。

【讨论】:

  • -D 标志在编译时更改代码。然后是-Wl,--wrap 之类的东西,它在链接时执行此操作。
  • 如果将-D 与预处理器令牌合并相结合,那么文本made_up_function_name 也不需要在任何makefile 或构建脚本中出现。
【解决方案5】:

当您使用链接器标志-r 或--relocatable 构建时,它也不会产生任何“未定义引用”链接错误消息。

这是因为-r 将链接新对象文件中的不同对象,以便稍后链接。

【讨论】:

    【解决方案6】:

    如果从未调用过function(),则它可能不会包含在可执行文件中,也不会搜索从中调用的函数。

    【讨论】:

    • 所以即使没有声明原型也可以编译然后也被链接?我认为至少应该声明原型,否则会产生解析错误,对吧?
    • @0verbose - 这取决于您使用的 C 标准。最初,不需要原型。以后只有当你有 int 以外的参数类型时。
    【解决方案7】:

    POSIX 链接器操作所依据的“标准”算法为代码编译和链接时没有任何错误留下了可能性。详情见这里:https://stackoverflow.com/a/11894098/187690

    为了利用这种可能性,应将包含您的function(我们称之为f.o)的目标文件放入库中。该库应该在编译器(和/或链接器)的命令行中被提及,但到那时,没有其他目标文件(在命令行前面提到过)应该对function 或存在的任何其他函数进行任何调用f.o。在这种情况下,链接器将没有理由从库中检索f.o。链接器将完全忽略f.o,完全忽略function,因此完全忽略对made_up_function_name 的调用。即使made_up_function_name 没有在任何地方定义,代码也会编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多