(环境:gcc 4.6,c ++ 11,glibc 2.13,binutils 2.21)
请考虑以下“关联”演示背景:
foo.h中:
#pragma once
#include <iostream>
void foo();
foo1.cpp :
#include "foo.h"
void foo()
{
std::cout << "foo1";
}
foo2.cpp :
#include "foo.h"
void foo()
{
std::cout << "foo2";
}
的main.cpp :
#include "foo.h"
int main()
{
foo();
}
生成文件:
compile: main.o foo1.o foo2.o
case1: compile
g++ -o case1.x main.o
case2: compile
g++ -o case2.x main.o foo1.cpp
case3: compile
g++ -o case3.x main.o foo1.o foo2.o
clean:
rm *.o *.x
我们有一个函数声明如下:
void foo();
我们有多个定义,一个在foo1.cpp中,另一个在foo2.cpp中。
我们将.cpp文件编译成.o文件:
$ make compile
没问题,生成了main.o,foo1.o和foo2.o。
案例1
然后我们尝试链接main.o:
$ make case1
error: undefined reference to 'foo()'
好的,main.o引用了foo但没有定义链接。
案例2
现在我们尝试链接main.o和foo1.o
$ make case2
foo1.o中有一个foo的定义,所以链接没有错误。
案例3
现在我们尝试链接main.o foo1.o和foo2.o
$ make case3
error: multiple definition of 'foo()'
链接器在foo1.o和foo2.o中找到foo的两个定义,因此它不是一个随机的,而是快速失败并且没有链接。
问题
我的问题是:
是否可以将foo1.cpp的foo版本(可能带有某种gcc属性或pragma)的定义标记为“weak”?特别是我希望案例1和案例2的行为保持不变,而案例3的行为更改为成功链接而没有警告或错误,并且foo2.cpp中foo的定义被链接(覆盖“弱”定义在foo1.cpp)。
是否可以在运行时测试(并分配给一个布尔变量)foo的弱版本是否被链接,还是强版本(显然没有执行该函数)。即在main中实现如下函数。
template<typename FunctionPtr>
bool is_weak_linked(FunctionPtr fp);
is_weak_linked(foo)应该在案例2中返回true而在案例3中应该返回false。
答案 0 :(得分:1)
至#1:
void foo() __attribute__((weak));
void foo()
{
...
}
#2:我不相信,不是你正在做的静态链接。该信息在链接时丢失。
修改
你总能抽象出你的方式#2。一些例子:
// Foo.h
extern void foo();
extern "C" void default_foo();
extern const bool is_weak_foo_linked;
template <void (*)()> bool is_weak_linked();
// Foo1.cc
extern "C" void default_foo() {...}
void foo() __attribute__((weak, alias("default_foo")));
extern const bool __attribute__((weak)) is_weak_foo_linked=true;
template <> bool is_weak_linked<foo>() __attribute__((weak));
template <> bool is_weak_linked<foo>() {return true;}
// Foo2.cc
void foo() {...}
extern const bool is_weak_foo_linked=false;
template <> bool is_weak_linked<foo>() {return false;}
// main.cc
#include "foo.h"
#include <iostream>
int main() {
foo();
std::cout<<is_weak_foo_linked<<std::endl;
std::cout<<is_weak_linked<foo>()<<std::endl;
std::cout<<(foo==default_foo)<<std::endl;
}