+++ title = "Generate function wrapper with macro magic" [taxonomies] tags = ["c++"] +++ **Short disclaimer at front**. This post discusses about c/cpp macros, which in general, I try to use as little as possible or avoid at all. However, they have their application and can be useful. All I want to say is, use the right amount of macros for the corresponding context and think about your colleagues if used in production. :^) --- Recently I had the need to wrap a list of c functions and perform some common work before and after each wrapped function had been invoked. Hence, the body of each wrapper function was identical. The wrappers were compiled and linked into a shared library which then was used for **LD_PRELOAD**ing. In this post I want to collect and archive a few approaches to generate the required boilerplate code using preprocessor macros. Going from top to bottom, the amount of macro code (*magic*?) increases. To inspect the generated code, one can use the following command with all the code examples from this post. ``` g++ -E file.cc | clang-format ``` > With the **-E** option, g++ stops after the preprocessor stage; output is > written to *stdout*. > Alternatively, one can just invoke the preprocessor **cpp file.cc**. To syntax check the code examples, one can use the following command. ``` g++ -fsyntax-only file.cc ``` ## Version 1 The first version provides a *function definition* like macro, here called `WRAP`. When creating a wrapper function, this macro is directly used to define the wrapper. One declares the signature in the WRAP macro, which is then followed by curly braces including the wrapper body. The benefit of this approach is that the wrapper implementation is quite explicit and a reader, not familiar with the WRAP macro, might have a good chance to reason about what the code is doing. The draw back is that bodies have to be repeated for each wrapper. ```cpp {{ include(path="content/2024-04-22-fn-wrapper-macro-magic/wrap-v1.cc") }} ``` > In the code examples, I use the `MOCK_WRAPPER_IMPL`1 > macro, to mock away the common pre and post work and to invoke the real > function. ## Version 2 The second version provides a simple approach to also generate the wrapper bodies by explicitly writing out a typed list of arguments and a list of argument names. The main drawbacks are that the wrapper definition as well as the body of the `WRAP` macro are somewhat obfuscated, which makes it hard for a reader to reason about the code. Additionally, the arguments must be specified twice, when defining a wrapper. ```cpp {{ include(path="content/2024-04-22-fn-wrapper-macro-magic/wrap-v2.cc") }} ``` ## Version 3 The third version provides macros to generate the list of typed arguments as well as the list of argument names. Then for the different *arity* of the wrapper function, corresponding `WRAP1, WRAP2` macros are provided to generate the boilerplate code with the correct number of arguments. The example only supports function with **one** or **two** arguments, but the code can easily be extended. ```cpp {{ include(path="content/2024-04-22-fn-wrapper-macro-magic/wrap-v3.cc") }} ``` ## Version 4 The fourth version improves the third one by automatically using the correct `TYPEDARGS` and `ARGS` macro depending on the *arity* of the wrapper function. This is achieved by dynamically constructing the correct macro name during preprocessing time. The technique to count the number of elements in the variadic argument list [__VA_ARGS__][va-args] is presented in [__VA_NARG__][va-narg]. ```cpp, hide_lines=41-100 {{ include(path="content/2024-04-22-fn-wrapper-macro-magic/wrap-v4.cc") }} ``` ## Appendix: Listify codegen data A hacker friend once showed me some neat macro magic, to organize data, relevant for generating code in some list, which can then be used at multiple places. Since it fits topic wise, I want to archive this technique here as well. The idea is that the list accepts a macro, which is applied to each entry. The following is an example, using the `WRAP` macro from [version 4](#version-4). ```cpp #define API(M) \ M(int, foo, const char*) \ M(int, bar, const char*, const char*) \ M(int, baz, char, int, unsigned) API(WRAP) ``` To close this appendix with some words the same great hacker friend once said: > *This is the excel-ification of cpp code*. ## References - Count number of elements in VA_ARGS [[ref][va-narg]] - Variadic macros [[ref][va-args]] - Preprocessor concatenation [[ref][cpp-concatenation]] - Preprocessor macro argument handling [[ref][cpp-macro-args]] - Preprocessor argument prescan [[ref][cpp-args-prescan]] ## Footnotes
**1)** In the examples above, **MOCK_WRAPPER_IMPL** is a macro. However it does not need to be one, as it can be seen in the [fn_hook.cc][fn-hook] example. [va-narg]: https://groups.google.com/g/comp.std.c/c/d-6Mj5Lko_s [va-args]: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html [cpp-concatenation]: https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html [cpp-macro-args]: https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html [cpp-args-prescan]: https://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html [fn-hook]: https://git.memzero.de/testground/cpp-templates/tree/fn_hook.cc