【问题标题】:visual studio c linker wrap option?Visual Studio C链接器包装选项?
【发布时间】:2015-11-18 21:09:31
【问题描述】:

来自这篇文章Unit testing with mock objects in C

这是通过使用 --wrap 链接器选项来完成的,该选项将包装函数的名称作为参数。如果测试是使用 gcc 编译的,调用可能如下所示:

$ gcc -g -Wl,--wrap=chef_cook waiter_test.c chef.c

在 Visual Studio 中编译 C 项目时如何执行此操作?

【问题讨论】:

  • +1 这也是我想知道的,看来在VS(即MSVC编译器)中只能使用#defines手动覆盖实际实现。

标签: c visual-studio linker cmocka


【解决方案1】:

ld 中的 --wrap 可以通过 MSVC 链接器中的 /ALTERNATENAME 选项进行模拟。

我们从两个编译单元开始,比如从foo.c 编译的foo.o,其外部函数在foo.h 中声明,main.omain.c 中声明。 (如果foo 已经编译为库,情况不会有太大变化。)

// foo.h
int foo();

// foo.c
int foo() {
    return 0;
}

// main.c
#include <stdio.h>
#include "foo.h"
int main() {
    int x = foo();
    printf("%s\n", x ? "wrapped" : "original");
}

int foo()的返回值为0,所以上面代码的sn-p会输出“original”。

现在我们用别名覆盖实际的实现:main.c 中的 #include "foo.h" 被替换为

#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")

让我解释一下这里发生了什么:

  1. #define foo real_foofoo.h中的函数声明修改为int real_foo()
  2. 但是,foo.o 中的符号仍然以int foo() 命名,而不是别名int real_foo()。这就是我们需要 /alternatename 链接器开关的原因。
  3. "/alternatename:real_foo=foo" 告诉链接器,如果找不到名为 real_foo 的符号,请在引发错误之前再次尝试 foo
  4. 显然没有int real_foo() 的定义。 MSVC 链接器将搜索 int foo() 并在每次出现 int real_foo() 时链接它。

由于之前的实现已被别名,现在我们通过宏将int foo() 重定向到我们的新实现:

int wrap_foo() {
    return real_foo() + 1;
}
#define foo wrap_foo

我们到这里就完成了。最后main.cpp 看起来像:

#include <stdio.h>

#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")

int wrap_foo() {
    return real_foo() + 1;
}
#define foo wrap_foo

int main() {
    int x = foo();
    printf("%s\n", x ? "wrapped" : "original");
}

内置MSVC,会输出“wrapped”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    相关资源
    最近更新 更多