【问题标题】:Wrapping C++ functions with GNU linker使用 GNU 链接器包装 C++ 函数
【发布时间】:2011-12-06 15:35:18
【问题描述】:

我非常喜欢 GNU 链接器功能来包装函数。我通常使用它来模拟,例如像rand() 这样的非确定性函数调用。考虑以下示例,我想为giveMeANumber 编写单元测试:

//number.cpp
int giveMeANumber() {
  return rand() % 6 + 1;
}

我可以使用 GNU 链接器功能包装对 rand 的调用,如下所示:

//test.cpp
extern "C" int __wrap_rand(void) {
return 4;
}

void unitTest() {
  assert giveMeANumber() == 5;
}

$ g++ test.cpp -o test number.o -Xlinker --wrap=rand

有什么方法可以对普通的 C++ 函数做同样的事情吗?以下不起作用,我猜是因为名称修改。但即使我尝试使用损坏的名称,它也不起作用。

//number.cpp
int foo() {
  //some complex calculations I would like to mock
}
int giveMeANumber() {
  return foo() % 6 + 1;
}

//test.cpp
extern "C" int __wrap_foo(void) {
return 4;
}

$ g++ test.cpp -o test number.o -Xlinker --wrap=foo

【问题讨论】:

  • 其实rand是一个确定性函数。它返回一个伪随机数序列。调用 rand 将返回与 srand 一起使用的任何给定种子的相同数字序列。
  • 好吧,太棒了,这是真的。但是为了使示例简短易读,我没有使用种子。
  • 您需要将__wrap_foo 重命名为getRandomNumber。 (xkcd.com/221)

标签: c++ linker mocking


【解决方案1】:

您还需要 extern "C" 要包装的函数(如果可能的话),或者您需要包装损坏的名称,例如 __wrap__Z3foov,然后将 --wrap=_Z3foov 传递给链接器。

正确使用下划线有点棘手。这对我有用:

$ cat x.cc
#include <iostream>
using namespace std;

int giveMeANumber();

int main() {
    cerr << giveMeANumber() << endl;
    return 0;
}

$ cat y.cc
int giveMeANumber() {
    return 0;
}

extern "C" int __wrap__Z13giveMeANumberv() {
    return 10;
}

$ g++ -c x.cc y.cc && g++ x.o y.o -Wl,--wrap=_Z13giveMeANumberv && ./a.out
10

【讨论】:

  • 要包装的 C++ 函数的 C 链接不是一个选项,因为该函数可能被重载,并且应该仍然可以从其他 C++ 函数调用它。我试图包装损坏的名称,但它不起作用。我所做的是:extern "C" int __wrap__Z3foov(void) { return 4; } void thisIsATest() { assert 5 == giveMeANumber(); } 以及链接器选项-Xlinker --wrap=_Z3foov。不幸的是,真正的foo 函数仍在被调用。有什么想法吗?
  • 我添加了一个例子。我花了一段时间才把所有的下划线都弄对了。
  • 感谢您的提问。我什至不知道--wrap。非常好。
  • 如果我们更改函数名称“giveMeANumber”,它会调用真正的函数并注意 _wrap__Z13....v 是函数名称和前缀之间的关系??
【解决方案2】:

您似乎正在尝试模拟函数和类以进行测试。您是否考虑使用 Google Mock

【讨论】:

  • 使用谷歌模拟不是我的选择。我只想在 GNU 链接器的帮助下完成这项工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 1970-01-01
  • 2018-11-15
  • 2013-08-14
  • 2019-02-19
  • 1970-01-01
相关资源
最近更新 更多