从下一个文件的范围中删除标题中包含的函数

时间:2016-06-28 20:38:33

标签: c

在我的项目中,我们大量使用C头,它提供了一个API来与外部软件进行通信。简而言之,在我们的项目中,错误更多地出现在调用这些头文件中定义的函数上(这是一个古老而丑陋的遗留代码)。

我想在调用这些函数时实现间接,所以我可以在调用实际的实现之前包含一些分析。

因为我并不是唯一一个从事这个项目的人,所以我想以这样的方式制作这些包装器:如果有人直接使用原始实现,那么应该会导致编译错误。

如果这些头文件是C ++源代码,我可以简单地创建一个namespace,将包含的文件包装在其中,并使用它实现我的函数(其他开发人员将能够使用原始实现::运算符,但只是无法直接调用它对我来说是足够的封装。但是标题是C源(我必须包含extern "C"指令包含),所以命名空间不会帮助我AFAIK。

我试着玩define s,但没有运气,就像这样:

#define my_func api_func
#define api_func NULL

上述代码我想要的是在预处理期间将my_func转换为api_func,同时直接调用api_func会产生编译错误,但是赢得了#39;工作是因为它实际上会将my_func翻译为NULL

所以,基本上,我想创建一个包装器,并确保访问API的唯一方法是通过这个包装器(除非其他开发人员做出一些解决方法,但这是不可避免的)。 请注意,我需要包含数百个函数,这些函数会在整个代码中多次显示。

我的包装器必须包含那些C头,但是我想让它们在我的包装器文件之外留下范围,并使它们对包含我的包装器的每个其他文件都不可用,但我想这是在C / C ++中是不可能的。

3 个答案:

答案 0 :(得分:1)

你有几个选择,其中没有一个很棒。

  • 如果您拥有遗留软件的来源,以便可以重新编译它,您只需更改API函数的名称,以便为包装函数腾出空间。如果您另外创建原始函数static并将包装器放在相同的源文件中,那么您可以确保仅通过包装器调用原始函数。例如:
static int api_func_real(int arg);

int api_func(int arg) {
    // ... instrumentation ...
    int result = api_func_real(arg);
    // ... instrumentation ...
    return result;
}

static int api_func_real(int arg) {
    // ...
}

预处理器可以为您提供帮助,但我毫不犹豫地推荐具体信息,但没有任何细节可以使用。

  • 如果您没有旧版软件的来源,或者您不愿意修改它,那么您需要让所有调用者调用您的包装器而不是原始函数。在这种情况下,您可以在使用#define更改每个原始函数名称之前修改标题或包含其他标题。 该标头不得包含在包含API函数实现的源文件中,也不得包含在提供包装函数实现的文件中。每个定义的形式如下:
#define api_func api_func_wrapper

然后,您将实现各种api_func_wrapper()函数。

这些情况的不同之处在于,如果更改遗留函数名称,那么这些函数之间的内部调用将通过带有原始名称的包装器(除非您也更改调用),但是如果您实现包装器新名称然后它们将仅在显式调用时使用,这对于遗留代码中的内部调用不会发生(除非您再次修改这些调用)。

答案 1 :(得分:1)

您可以执行类似

的操作

[你的包装器的包含文件]

int origFunc1 (int x);
int origFunc2 (int x, int y);

#ifndef WRAPPER_IMPL
#define origFunc1 wrappedFunc1
#define origFunc2 wrappedFunc2
#else
int wrappedFunc1(int x);
int wrappedFunc2(int x, int y);
#endif

[你的包装器实现]

#define WRAPPER_IMPL
#include "wrapper.h"

int wrapperFunc1 (...) {
   printf("Wrapper1 called\n");
   origFunc1(...);
}

您的包装器的C文件显然需要{/ 1}} #define 之前包括标头。

这既不好也不干净(如果有人想作弊,他可以简单地定义WRAPPER_IMPL),但至少一些方式。

答案 2 :(得分:1)

在Linux中有两种方法可以包装或覆盖C函数:

Hello World from B; Hello World from A

可以在以下位置找到完整的文章: var iTest = 0; if (iTest) { let sText = "This is a template string which can contain variables like ${iTest}"; console.log(sText); } else if (!iTest) { let fnc = (iRadius, iPi = 3.14) => { console.log("The area of the circle with the radius ${iRadius}cm is ${Math.round(iPi * iRadius * iRadius)}cm²"); } fnc(3.14); } else { /* This is never going to be called since else if is already handling the only option besides the if */ } var fnc = (iAlpha, iBravo, cb) => { cb(iAlpha + iBravo); } fnc(84,255,(iResult) => { console.log(iResult); });