用宏包装函数(不重命名)C

时间:2014-09-17 03:26:48

标签: c macros c-preprocessor

我有兴趣在现有函数调用周围添加一些额外的逻辑,通过将它们包装而不用重命名它们。 (仅用于测试)

我发现的现有解决方案依赖于将函数包装在不同名称的宏中,这可能意味着更改了大量代码。

有什么建议吗?


注意,我知道LD_PRELOAD,但我有兴趣使用宏来检查传递给函数的参数(例如,使用_Generic)。

2 个答案:

答案 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只需要intdouble),而不是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)