我想通过编译器开关为函数启用钩子(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_defn
和 args_list
部分。关于c - 在 C 中使用宏进行函数 Hook ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60099820/