c - 在 C 中使用宏进行函数挂钩
问题描述
我想通过编译器开关为函数启用钩子。我想得到以下结果:
#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
}
函数名称、返回类型、参数数量和类型应该是可变的。但是钩子等的名称应始终包含具有相同后缀的函数名称,如图所示。我的梦想是得到这样的东西:
#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
}
有没有人有一个想法,如何以一种通用的方式解决这个问题,这不会对可读性产生太大影响?还允许在挂钩函数等之前包含一个文件。
编辑:我的主题就像 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
在代码中编写调用和每个挂钩函数的宏定义。您必须为每个挂钩函数定义 pre-hook 和 post-hook 函数。
没有一种简单的方法可以避免宏 AFAIK的args_defn
and部分。args_list
推荐阅读
- c# - 在 Typescript(Angular 8)中调用 subscribe() 时无法访问返回的对象的值
- python - PyQt5 将 textChanged 信号连接到 QPlainTextEdit
- sql - json key:...,value:.... 到 postgresql 中的 value_key:value_value
- python - Python基于关键字列表过滤行的快速方法
- cmake - 不能告诉 cmake 使用 vcpkg 作为库链接
- c++ - 什么分配一个我不想等于任何可能输入的变量?
- python - 在python中查找多列之间的计数
- oauth - Keycloak Google 身份提供商错误:“身份令牌不包含托管域参数”
- android - 数据库助手对象在运行时返回 null-Android
- java - 如何检查 3D 矩阵上只有 0 的行数?