在链接时弱定义函数,并测试覆盖
Weakly defining function at link-time, and testing for override
(环境: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
然后我们试着把主链接起来。o:
$ make case1
error: undefined reference to 'foo()'
好的,main.o引用了foo,但没有链接任何定义。
情况2
现在我们尝试链接main.o和foo1.o
$ make case2
foo1.o中只有一个foo的定义,所以它的链接没有错误。
案例3
现在我们尝试链接main.ofoo1.o和foo2.o
$ make case3
error: multiple definition of 'foo()'
链接器在foo1.o和foo2.o中找到了两个foo的定义,因此它没有采用随机的定义,而是快速失败并出现错误,并且没有链接。
问题
我的问题是:
是否可以将foo1.cpp版本的foo的定义(可能带有某种gcc属性或pragma)标记为"弱"?具体地说,我希望情况1和情况2的行为保持不变,而情况3的行为更改为成功链接而没有警告或错误,并且链接了foo2.cpp中foo的定义(覆盖foo1.cpp中的"弱"定义)。
是否可以在运行时测试(并分配给布尔变量)是链接了foo的弱版本,还是链接了强版本(显然不执行函数)。即主要实现如下功能。
template<typename FunctionPtr> bool is_weak_linked(FunctionPtr fp);
is_weak_linked(foo)在情况2中应返回true,在情况3中应返回false。
至#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;
}
- 专门化模板覆盖函数/避免对象切片
- 为什么编译器不检查被覆盖函数的存储类?
- 如何使基类从子类调用覆盖函数
- 为什么 MSVC 在使用正确的签名覆盖函数时会产生 C3668 错误?
- 当要测试的函数需要用户输入时,如何制作驱动程序函数?
- 为什么调用具有通用或 r 值引用的重载覆盖函数是不明确的?
- 如何在C++中覆盖函数
- Arduino 可覆盖函数
- 按每个顺序测试每个函数组合
- 我们应该修改单元测试的函数签名吗?
- 为什么我们不能在C++中覆盖函数指针?
- 在多级继承中重写,中间派生类未覆盖函数
- 测试DLL函数的最佳方法是什么
- 是否可以测试constexpr函数是否在编译时求值
- 通过剥离可变宏/模板/函数对来测试成员函数
- C++获取指向受保护覆盖函数的指针
- 内联失败:可以在链接时覆盖函数体
- 死亡测试时函数调用的评估错误
- C++ 调用覆盖函数会导致调用基函数
- 在链接时弱定义函数,并测试覆盖