我想通过编译器开关为函数启用钩子(Hook)。我想得到以下结果:

#ifdef COMPILER_SWITCH
static inline int Foo_HOOKED(int x, int y);

int Foo(int x, int y)
{
    int rval;

    Foo_PRE_HOOK();
    rval = Foo_HOOKED(x,y);
    Foo_POST_HOOK();

    return rval;
}

static inline int Foo_HOOKED(int x, int y)
#else
int Foo(int x, int y)
#endif  // COMPILER_SWITCH
{
    // Implementation of Foo
}

函数名称、返回类型、数量和参数类型应该是可变的。但是钩子(Hook)等的名称应始终包含具有相同后缀的函数名称,如图所示。我的梦想是得到这样的东西:
#ifdef COMPILER_SWITCH
#define HOOKED_FUNCTION(x) <magic>
#else
#define HOOKED_FUNCTION(x) #x
#endif

HOOKED_FUNCTION(int Foo(int x, int y))
{
    // Implementation of Foo
}

有没有人有想法,如何以通用的方式解决这个问题,这不会太大影响可读性?还允许在 Hook 函数等之前包含一个文件。

编辑:我的主题就像 C++ 中的守卫。不幸的是我在...
#define HOOKED_FUNCTION  hook_t my_hook

class hook_t
{
public:
    hook_t() { pre_hook(); }
    ~hook_t() { post_hook(); }
};


int Foo(int x, int y)
{
#if COMPILER_SWITCH
    HOOKED_FUNCTION;
#endif
    // implementation of Foo()...
}

最佳答案

这是否足够接近?

//#define COMPILE_SWITCH

#ifdef COMPILE_SWITCH

#define HOOK_FUNCTION(name, rtype, args_defn, args_list) \
    static rtype (name)args_defn; \
    extern void name ## _PRE_HOOK(void); \
    extern void name ## _POST_HOOK(void); \
    static inline rtype name ## _HOOKED args_defn { \
        name ## _PRE_HOOK(); \
        rtype rval = (name)args_list; \
        name ## _POST_HOOK(); \
        return rval; \
    }

HOOK_FUNCTION(Foo, int, (int x, int y), (x, y))
#define Foo(x, y) Foo_HOOKED(x, y)

HOOK_FUNCTION(Bar, double, (int x, int y, int z), (x, y, z))
#define Bar(x, y, z) Bar_HOOKED(x, y, z)

#endif /* COMPILE_SWITCH */

#include <stdio.h>
#include <math.h>

static int (Foo)(int x, int y)
{
    int z = x * x + y * y;
    return z;
}

static double (Bar)(int x, int y, int z)
{
    return sqrt(x * x + y * y + z * z);
}

int main(void)
{
    int x = 3;
    int y = 5;
    int z = Foo(x, y);
    printf("x = %d, y = %d, z = %d\n", x, y, z);
    printf("x = %d, y = %d, z = %d, r = %.3f\n", x, y, z, Bar(x, y, z));
    return 0;
}

#ifdef COMPILE_SWITCH

void Foo_PRE_HOOK(void)
{
    printf("-->> Foo() (%s)\n", __func__);
}

void Foo_POST_HOOK(void)
{
    printf("<<-- Foo() (%s)\n", __func__);
}

void Bar_PRE_HOOK(void)
{
    printf("-->> Bar() (%s)\n", __func__);
}

void Bar_POST_HOOK(void)
{
    printf("<<-- Bar() (%s)\n", __func__);
}

#endif /* COMPILE_SWITCH */

这将编译并运行:
$ rmk -u hook67 UFLAGS=-UCOMPILE_SWITCH && hook67
    gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes        -UCOMPILE_SWITCH hook67.c -o hook67
x = 3, y = 5, z = 34
x = 3, y = 5, z = 34, r = 34.496
$ rmk -u hook67 UFLAGS=-DCOMPILE_SWITCH && hook67
    gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes        -DCOMPILE_SWITCH hook67.c -o hook67
-->> Foo() (Foo_PRE_HOOK)
<<-- Foo() (Foo_POST_HOOK)
x = 3, y = 5, z = 34
-->> Bar() (Bar_PRE_HOOK)
<<-- Bar() (Bar_POST_HOOK)
x = 3, y = 5, z = 34, r = 34.496
$
rmk 程序是 make 的变体; -u 标志表示“无条件编译”。 makefile 有一个 CFLAGS 宏,其中包括 ${UFLAGS}(用于用户标志)——UFLAGS 仅在命令行上设置。

您可以将 HOOK_FUNCTION 的宏定义放入标题中。您仍然需要在代码中编写 HOOK_FUNCTION 调用和每个 Hook 函数的宏定义。您必须为每个 Hook 函数定义 Hook 前和 Hook 后函数。

没有一种简单的方法可以避免宏 AFAIK 的 args_defnargs_list 部分。

关于c - 在 C 中使用宏进行函数 Hook ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60099820/

10-16 23:58