0

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).

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • As an alternative to macro magic, you find might answers to [this question](http://stackoverflow.com/questions/617554/override-a-function-call-in-c) interesting. Especially [the one about LD_PRELOAD](http://stackoverflow.com/a/618059/1717300) and [the one about `--wrap`](http://stackoverflow.com/a/617606/1717300). – hyde Sep 17 '14 at 04:52

2 Answers2

2

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);
}
rici
  • 234,347
  • 28
  • 237
  • 341
  • Defining or undefining a standard macro causes undefined behavior. I believe this applies even if you don't include a header with its definition, but even if you include any standard header. (I might just be applying a rule from C++, though.) – Potatoswatter Sep 17 '14 at 04:23
  • 1
    @Potatoswatter: C is more liberal. "Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified *if any of its associated headers is included* unless explicitly stated otherwise" – rici Sep 17 '14 at 04:27
  • @Potatoswatter: Also, it seems (§7.1.4) to be valid to `#undef` a function-like macro defined by a standard library header if that function-like macro shadows the definition of a standard library function. The standard library is required to make standard functions available as functions, even if it chooses to use function-like macros to shadow them for efficiency (or whatever). – rici Sep 17 '14 at 04:33
  • @rici - Ok. the point of confusion here, is that the defines for the functions `cbrt`, need to be included first (in retrospect its obvious - but including the header after the define will obviously break). – ideasman42 Sep 17 '14 at 04:38
  • @ideasman42: Added that to the answer, with a quote from the standard. – rici Sep 17 '14 at 05:25
1

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)
ideasman42
  • 42,413
  • 44
  • 197
  • 320