Wrapping functions with macros (without renaming) C

↘锁芯ラ 提交于 2020-01-11 14:14:06

问题


Im interested to add in some extra logic around existing function calls, by wrapping them without renaming them. (just for a test).

The existing solutions I found rely on wrapping a function in a macro of a different name, which can mean changing a lot of code.

Any suggestions?


Note, I'm aware of LD_PRELOAD, but am interested to use macro's to be able to inspect the arguments passed to the function (using _Generic for example).


回答1:


There's normally no need to rename macro-wrapped functions because inside the expansion of a macro, the macro's name is not expanded.

Here's an example straight from the C11 standard:

#define cbrt(X) _Generic((X),               \
                        long double: cbrtl, \
                        default: cbrt,      \
                        float: cbrtf        \
                        )(X)

Of course, you'll run into problems if you've #include <tgmath.h> because in that case you'll already have type-generic macros, such as the above, and you won't be able to redefine sqrt (unless you #undef it). And you must #include <math.h> before defining that macro.

Even so, you're treading on thin ice. The standard reserves the names of standard library functions, and insists that (§7.1.3/2):

If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.

The referenced section 7.1.4 does allow you to #undef a function-like macro which shadows a standard-library function, but it is not clear to me that you are allowed to subsequently redefine it. YMMV.


If you wanted to use _Generic to call a wrapper function, you can still make that work without renaming the original function. For example:

#include <nanny.h>

/* In this file, you can't call nanny(char), and if you call it
 * with an unsigned argument, we'll insert an additional check
 */

#define nanny(X) _Generic((X), int: nanny, unsigned:nanny_wrapper)(X)

int nanny_wrapper(unsigned x) {
  assert(x < INT_MAX);
  /* The redundant parentheses prevent macro expansion */
  return (nanny)(x);
}



回答2:


For example, lets say I want to check the types on a function call.

A simple case, I want to check that sqrt only takes (int or double), not float.

Here is a method that works OK.

/* 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)

This works but has some drawbacks.

  • Must include <math.h>, or at least define sqrt since we dont know if the static function is called or not.
  • Defines a function all over which may be unused. though __attribute__((__unused__)) works in works in GCC/Clang.
  • All output must have access to the function symbol, even if it ends up not using sqrt.

Edit!


This does in fact work, the header just needs to be included first (obviously - in retrospect)

#include <math.h>
#define sqrt(f) _Generic((f), int: sqrt(f), double: sqrt(f))

Heres a trick to check sqrt isn't called with float and sqrtf isn't called with double

#include <math.h>
#define sqrt(X)  _Generic((X), float:  NULL, default: sqrt)(X)
#define sqrtf(X) _Generic((X), double: NULL, default: sqrtf)(X)


来源:https://stackoverflow.com/questions/25881785/wrapping-functions-with-macros-without-renaming-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!