Wrapping functions with macros (without renaming) C

前端 未结 2 1224
日久生厌
日久生厌 2021-01-29 02:29

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

The existin

相关标签:
2条回答
  • 2021-01-29 03:08

    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)
    
    0 讨论(0)
  • 2021-01-29 03:13

    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);
    }
    
    0 讨论(0)
提交回复
热议问题