重新定义发生在哪个程序中?编译或链接时间

redefinition happend in which procedure? compile or link time?

本文关键字:程序 编译 时间 链接 新定义 定义      更新时间:2023-10-16

如果我定义了一个函数两次,我将得到一个重新定义错误消息,但是我很困惑,重新定义发生在编译或链接时间?

和为什么你可以重写malloc在libc没有重定义错误?

当您有两个具有相同原型或签名的函数时(函数签名由函数名称,参数数量和参数类型组成,不包括返回类型),您将获得函数重定义错误。

如果编译器看到两个函数具有相同的签名,这是一个编译时错误:

int foo(int a);
double foo(int b);

为什么可以在库中重写函数调用?让我们看看如何将代码构建为可执行文件:

  • 编译器被每个源文件调用并输出一个目标文件:任何无法解析的函数调用(即调用不同文件中的函数)都是一个外部符号,链接器必须解析。
  • 链接器获取所有的目标文件并尝试解析所有的符号;但它是以先到先得的方式做到这一点的。对于外部符号,它将考虑它找到的第一个定义,而不担心同一符号可能有更多的定义。

所以,链接器实际上允许你重写函数的行为。这完全取决于文件链接的顺序——它找到的第一个函数定义就是用来解析符号的函数定义。

希望这能对这件事有所帮助。

两者皆可。它也可能来自程序员编辑源代码或修改构建脚本。

当链接器发现两个名称相同的东西(符号)时,会发出"Redefinition"错误。

链接器发现两个名称相同的符号有很多原因。一些可能性(有许多排列)包括;
  • 在link命令中指定对象文件两次。这通常是由于构建脚本中的错误造成的。
  • 包含相同函数定义的两个对象文件。这是由代码复制造成的——例如,将函数定义复制到不同的源文件中,然后对这些源文件进行编译和链接。它也可能是由于预处理器的拙劣操作(例如,#include一个包含两个源文件的全局变量定义的文件)。

导致上述情况的原因通常是程序员的错误(例如,在构建脚本中提供了错误的链接器命令,滥用预处理器,在项目之间复制和粘贴代码)。

像libc这样的库中的函数经常被"覆盖"的原因是,如果链接器在目标文件中找不到符号,它通常只在库中查找符号。因此,如果一个目标文件定义了malloc(),链接器将解析对它的所有调用,而不是尝试使用库中的版本来解析。这种事情是相当危险的,因为库中的一些其他函数(例如,甚至在libc中)可能直接解析到原始的malloc()(例如,一些调用可能是内联的),这可能会导致不可预测的行为。这种行为也是特定于链接器的:尽管这种事情在unix/linux变体中很常见,但在某些系统中,链接器的工作方式不同。