c++ - 重写静态库中的 C 函数

标签 c++ c unit-testing g++ cygwin

我收到多个定义错误,但不明白原因。

我正在 Cygwin 上使用 g++ 编译 C 代码。我正在使用单元测试框架(google test,它是 C++,这就是我不使用 gcc 的原因)。单元测试源文件 #includes 包含我想要进行单元测试的函数的 .c 文件 (fileA.c),实质上使其成为所述文件的扩展名,然后我编译单元测试源文件。被测试的函数调用在 fileB.h 中声明并在 fileB.c 中定义的函数。有点像Override a function call in C 。我没有显示包含防护,但本质上精简的代码如下所示:

文件B.h

typedef void * pClass; // to hide the "class" in the .c file
extern pClass pObject1;

void do_something_with_object( void * );

文件B.c

#include "FileB.h"

typedef struct myclass {
    int stuff;
} myclass;

myclass Obj1 = { initial_value };

void *pObj1 = &Obj1;

void do_something_with_object( void *arg) {
    // do stuff, casting to myclass and verifying it's the right kind
}

文件A.h

#include "fileB.h"

void myfunc( void );

文件A.c

#include "fileA.h"

void myfunc( void ) {

    do_something_with_object( pObj1 );
}

utest_fileA.cpp

#include "../fileA.c"
// google test infrastructure stuff not shown
TEST(testname, testcase) {
    myfunc();
}

fileB 的符号链接(symbolic link)到包含所有生产代码的静态库中。静态库是用 g++ 编译的,因此不存在 extern "C" 问题。 utest_fileA.cpp 的 makefile 静态链接到该库中。到目前为止,一切都很好。现在,我想提供我自己的 do_something_with_object 的假版本,这样我就可以监视传入的内容,以确保 myfunc 使用正确的参数调用 do_something_with_object 。我不想仅仅为了支持这个单元测试而修改生产代码。因此,我在单元测试源的编译单元中进一步创建了 do_something_with_object 的假版本:

static void * myspy;
void do_something_with_object( void * arg) {
    myspy = arg;
}

这个想法是,单元测试将使用假定义,并且由于它有一个定义,因此不会费心在静态库中查找它,并且不会有冲突。通常这是有效的。但在我现在遇到的情况下,我遇到了 do_something_with_object() 的多个定义错误,首先找到假的,然后找到真正的。我没有看到与此有效的情况有什么不同,但显然我错过了一些东西。可能是什么原因造成的?我应该寻找什么?尝试将 utest_fileA.o 与 libMyLib.a 链接时失败。它使用 -static 标志。我尝试了一些我在 stackoverflow 上其他地方看到的建议,例如 -z muldefs,但 Cygwin 不喜欢这样,我真的很想了解发生了什么。

最佳答案

出现多个定义的原因是fileB.h中的“extern pClass Object1”。作为未解析的外部,当目标文件包含它时,链接器会拉入定义它的对象,即 fileB.o。链接器拉入整个 fileB.o 而不仅仅是其中的单个符号,因此函数定义也被拉入。因此,当单元测试代码编译并具有 spy 定义时,它可以正常编译。但是当链接器尝试链接静态库时,它找到了另一个定义,因此链接失败。

我没有尝试通过让链接器首先找到 spy 版本来覆盖静态库中的函数调用,而是最终为 spy 提供了一个稍微不同的名称,并使用预处理器将其交换以进行单元测试。这使得生产代码保持不变。它与 Override a function call in C 中选择的答案类似,但不完全相同。 ,因为 spy 及其预处理器指令是在一个单独的文件中定义的,可以包含在任何单元测试中,所以不需要在特定的头文件中注册替换。

关于c++ - 重写静态库中的 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7988043/

相关文章:

c++ - 用类实例的指针初始化是C++中唯一的吗?

c - 下面的格式说明符在做什么?

java - 参数化 JUnit+JUnitParams 测试不适用于具有

c++ - 如何找到一个号码的日志?

C++11 返回值和错误对

c - C中数组转换的问题

angular - 在带有单元测试 angular + jasmine 和 SpyOn 的 switchMap 中永远不会调用函数

android - 如何将数据库测试夹具从我的单元测试应用程序传输到设备

c++ - 从数据库填充 QTreeView 作为父节点和子节点

c - 根据其元素之一对结构进行排序