2015-07-13 76 views
0

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

为什么你可以覆盖malloc libc没有重定义错误?

+2

重新定义在链接阶段发生。 – Ishmeet

+0

是的,您可以覆盖malloc(),因为如果符号尚未被您自己的代码满足,链接器只会查看libc。通用建议:除非你真的*知道你在做什么,否则不要试用。 – DevSolar

回答

0

其中之一或两者。它也可能源于程序员编辑源代码或修改构建脚本。

当链接器找到两个具有相同名称的东西(符号)时,会发出“重新定义”错误。

链接器可能会找到两个具有相同名称的符号的原因很多。一些可能性(有许多排列)包括;

  • 目标文件在链接命令中指定了两次。这通常是由构建脚本中的错误造成的。
  • 两个包含相同函数定义的目标文件。这是代码复制的结果 - 例如,函数定义被复制到不同的源文件中,然后进行编译和链接。它也可能来自与预处理器的猴业务(例如#include ing文件包含由两个源文件定义的全局变量)。

的东西,如上述的原因通常是程序员错误(例如,在构建脚本供给坏接头命令,项目之间的预处理器,复制和粘贴代码的误用。

原因在库中的函数像libc通常可以被“重载”,就是链接器通常只在库中找到符号,如果它在对象文件中找不到它们的话,那么,如果一个目标文件定义了malloc(),链接器将解析所有的调用,而不是尝试在库中使用版本来解析这种事情是相当危险的,因为库中的一些其他函数(例如,甚至在libc中)可能直接解析为原始的malloc()(例如一些调用可能被内联),这可能会导致不可预知的行为。这种行为也是特定于链接器的:虽然这种情况在unix/linux变体中很常见,但有些系统中连接器的做法各不相同。

1

如果您有两个具有相同原型或签名的函数(函数签名由参数和参数类型的函数名称数量构成,不包含返回类型),则会得到函数重定义错误。

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

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

为什么你可以重写库函数调用?让我们来看看代码是如何建成的可执行文件:

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

因此,链接器实际上允许您覆盖函数的行为。这一切都取决于文件链接的顺序 - 它找到的第一个函数定义是用于解析符号的函数。

希望对此有所了解。

+0

谢谢Pandrei, 做的“先到先得”方式只适用于共享库吗? 这里是我想要的,main.cpp调用def1.cpp和def2.cpp中定义的函数: gcc main.cpp def1.cpp def2.cpp //多重定义错误 但是 gcc main.cpp def1。所以def2.so //是的,先到先得的方式 有什么区别? –

+0

@ SamH.W不,它不适用于图书馆;实际上链接器并不知道区别;它只接收一堆目标文件并尝试解析这些符号。试试这个:一个带有函数原型的头文件,两个源文件,每个带有它自己的实现,并在main()中调用该函数。即使您对同一个函数有两个不同的实现,也应该创建它。 – Pandrei

相关问题