下面的代码是我看到的问题的简化版本;基本上,外部函数testprint()
最终调用printf()
中定义的test_xprintf.cpp
而不是标准printf()
。
(是的,代码看起来很奇怪,但它意味着代表问题,因此它本身并不一定有意义。)
为什么链接器链接到printf()
中定义的test_xprintf
?这是预期的行为还是依赖于工具?
//
// test_xprintf.cpp
//
#include <iostream>
#include <stdio.h>
#include <stdarg.h>
#include "test_dbgprintf.h"
/**
*
* There are 3 files in total:
* - test_xprintf.cpp
* - test_dbgprintf.h
* - test_dbgprintf.cpp
*
* Create a static C lib from test_dbgprintf.c and link with test_xprintf.cpp
*
* gcc -Wall -g -c -o test_dbgprintf.o test_dbgprintf.c &&
* ar -rcs libtest_dbgprintf.a test_dbgprintf.o &&
* g++ -Wall test_xprintf.cpp -L. -ltest_dbgprintf -I.
*/
extern "C" int printf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
return -1;
}
int main()
{
// testprint() is a shell function which simply calls printf.
// If the printf function above is called, the return value will be -1.
int ret = testprint(4);
std::cout << "Ret value is " << ret << std::endl;
return ret;
}
//
// test_dbgprintf.h
//
#ifndef TEST_DBGPRINTF_H
#define TEST_DBGPRINTF_H
#if defined (__cplusplus)
extern "C" {
#endif
int testprint(int num);
#if defined (__cplusplus)
}
#endif
#endif
//
// test_dbgprintf.c
//
#include <stdio.h>
int testprint(int num)
{
// By right this should be calling the std printf but it is linked to the printf in test_printf.cpp instead.
return printf("This is called from testprint %d\n", num);
}
答案 0 :(得分:2)
这是GNU链接器的已知行为。解析符号时,它只会检测.o之间的多个定义;如果在.o中没有找到定义,它只会求助于图书馆;然后它将在第一场比赛后停止搜索。
这是默认行为。您可以使用--whole-archive
覆盖它,但这可能会使您生成的模块膨胀。
答案 1 :(得分:1)
好的,我认为在阅读了这篇非常有用的blog之后,我找到了一个合理的解释。
这取决于链接顺序。这是我掩饰的东西,但看着我链接库的方式:
g++ -Wall test_xprintf.cpp -L. -ltest_dbgprintf -I.
将其扩展为两个步骤:
g++ -Wall -g -c -o test_xprintf.o test_xprintf.cpp
g++ -L. test_xprintf.o -ltest_dbgprintf -I.
我认为发生的事情是链接器:
printf()
test_xprintf
test_xprintf
时,它找到了未定义的符号printf
printf()
并愉快地将它们链接在一起。最后我认为libC是联系在一起的,这解释了为什么它没有看到它。
根据解释,我相信行为是预期的。
答案 2 :(得分:0)
您的额外printf
符号(作为C函数可见)会使链接器混乱。有可能,您还应该看到有关多重定义符号的链接器警告。
该标准甚至不考虑这种意义上的多重定义符号(更不用说翻译单元之外的任何内容)。
典型的链接器将绑定第一个匹配的符号(在某种意义上&#34;第一个&#34;)并为任何匹配的附加内容发出警告。
总结一下:这种行为完全取决于链接器的实现。
答案 3 :(得分:0)
在某些编译器中,std库被视为具有弱连接。 您定义的符号始终具有强大的链接,除非使用某些属性或类似定义,但默认情况下它们是链接的“强”#34;。
这意味着您的definde符号与标准符号之间的任何冲突符号将被解析为您提供的符号,这些符号是强大的&#34;的。
当我遇到这个问题时(使用CodeWarrior&#39; ColdFire编译器),我总是得到一个链接器警告:
Symbol _sprintf multiply defined in printf.c() and libc.a(printf.o )
Ignoring the definition in libc.a(printf.o )
可能你会看到类似的警告。
为什么有时需要在std lib中使用这种链接?好吧,在嵌入式系统中,也许某些功能对于处理器执行来说太重了,一个例子就是printf函数(不是printf本身,因为它只是一个包装器,我认为它是vsprintf或类似的,但我不是&# 39;记住哪一个,这很长(有时几乎占了整个记忆的1/4),所以我必须提供自己的简化版本。
我不知道这是标准的,还是仅依赖于链接器。