我有兴趣在现有函数调用周围添加一些额外的逻辑,通过将它们包装而不用重命名它们。 (仅用于测试)。
我发现的现有解决方案依赖于将函数包装在不同名称的宏中,这可能意味着更改了大量代码。
有什么建议吗?
注意,我知道LD_PRELOAD
,但我有兴趣使用宏来检查传递给函数的参数(例如,使用_Generic
)。
答案 0 :(得分:2)
通常不需要重命名宏包装函数,因为在宏的扩展中,宏的名称不会扩展。
这是一个直接来自C11标准的例子:
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
当然,如果你#include <tgmath.h>
,你会遇到问题,因为在这种情况下你已经有了类型通用的宏,如上所述,你将无法重新定义{ {1}}(除非你sqrt
)。在定义该宏之前,您必须#undef
。
即便如此,你还是在踩着薄冰。该标准保留了标准库函数的名称,并坚持(§7.1.3/ 2):
如果程序在保留它的上下文中声明或定义标识符(除了7.1.4允许的标识符),或者将保留标识符定义为宏名称,则行为未定义。
引用的第7.1.4节允许你#include <math.h>
一个类似于函数的宏,它会影响标准库函数,但我不清楚你是否可以随后重新定义它。 YMMV。
如果您想使用#undef
来调用包装函数,您仍然可以在不重命名原始函数的情况下完成该工作。例如:
_Generic
答案 1 :(得分:1)
例如,假设我想检查函数调用上的类型。
一个简单的案例,我想检查sqrt
只需要int
或double
),而不是float
。
这是一种正常的方法。
/* add this to a header or at the top of the source-code */
#include <math.h>
static typeof(&sqrt) sqrt_wrap = sqrt;
#define sqrt(f) (_Generic((f), int: sqrt_wrap, double: sqrt_wrap))(f)
这有效但有一些缺点。
<math.h>
,或者至少定义sqrt
,因为我们不知道是否调用静态函数。__attribute__((__unused__))
适用于GCC / Clang。sqrt
。编辑!
这确实有效,首先需要首先包含标题(显然 - 回想起来)
#include <math.h>
#define sqrt(f) _Generic((f), int: sqrt(f), double: sqrt(f))
这是一个检查诀窍sqrt
未使用float
调用,而sqrtf
未使用double
调用
#include <math.h>
#define sqrt(X) _Generic((X), float: NULL, default: sqrt)(X)
#define sqrtf(X) _Generic((X), double: NULL, default: sqrtf)(X)