diff options
Diffstat (limited to 'content/2024-04-24-fn-wrapper-macro-magic/index.md')
-rw-r--r-- | content/2024-04-24-fn-wrapper-macro-magic/index.md | 105 |
1 files changed, 80 insertions, 25 deletions
diff --git a/content/2024-04-24-fn-wrapper-macro-magic/index.md b/content/2024-04-24-fn-wrapper-macro-magic/index.md index fe45614..708336b 100644 --- a/content/2024-04-24-fn-wrapper-macro-magic/index.md +++ b/content/2024-04-24-fn-wrapper-macro-magic/index.md @@ -6,25 +6,23 @@ 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. :^) +This post discusses about c/cpp macros, which I generally try to minimize or +avoid altogether. However, they do have their applications and can be useful. +All I want to say is, use the right amount of macros for the specific context +and consider 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. +Recently I had the need to wrap a list of c functions and execute some common +task before and after each wrapped function call. Hence, the body of each +wrapper function was identical. Theses 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. +required boilerplate code using preprocessor macros. Progressing 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 +To examine the generated code, one can use the following command with all the code examples from this post. ``` g++ -E file.cc | clang-format @@ -51,7 +49,7 @@ 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") }} +{{ include(path="content/2024-04-24-fn-wrapper-macro-magic/wrap-v1.cc") }} ``` > In the code examples, I use the `MOCK_WRAPPER_IMPL`<sup><a href="#sup-1">1</a></sup> @@ -70,7 +68,7 @@ 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") }} +{{ include(path="content/2024-04-24-fn-wrapper-macro-magic/wrap-v2.cc") }} ``` ## Version 3 @@ -84,7 +82,7 @@ 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") }} +{{ include(path="content/2024-04-24-fn-wrapper-macro-magic/wrap-v3.cc") }} ``` ## Version 4 @@ -98,19 +96,75 @@ 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") }} +{{ include(path="content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc") }} +``` +> The implementation to handle empty arguments **CPP_ARGC() == 0** uses a gcc +> extension for the **##** operator. This is also supported by clang, but not +> by msvc. Maybe I will come back in the future to update this, if I have the +> need. + +## Appendix: CONCAT1 and CONCAT2? + +> *Macro arguments are completely macro-expanded before they are substituted +> into a macro body, unless they are stringized or pasted with other tokens +> [..]* - [gcc][cpp-args-prescan] + +```cpp +#define FOO() ABC + +#define CONCAT2(lhs, rhs) lhs ## rhs +#define CONCAT1(lhs, rhs) CONCAT2(lhs, rhs) + +CONCAT2(MOOOSE_, FOO()) +// expands to: +// MOOOSE_FOO() + +CONCAT1(MOOOSE_, FOO()) +// expands to: +// MOOOSE_ABC ``` ## 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. +A hacker friend once showed me some neat macro magic for organizing data +relevant to code generation within a list that can be reused in multiple +contexts. + +I want to archive this technique here, as it fits well in the topic. + +The idea is that the list can accept a macro, which is then applied to each +entry. The processing macros, may not need to use all the elements in an entry. -Since it fits topic wise, I want to archive this technique here as well. +The example below is somewhat arbitrary and one may not see the benefit, but it +is serves to demonstrate the technique. However, this technique really shines +when dealing with larger datasets that are used in different locations to +generate code. + +```cpp +#define EXCEPTIONS(M) \ + M(ill_opc , "Illegal opcode") \ + M(mem_fault, "Memory fault") \ + M(inv_perm , "Invalid permissions") + +enum exception { +#define ELEM(e, _) e, + EXCEPTIONS(ELEM) +#undef ELE +}; + +const char* describe(exception e) { + switch (e) { +#define CASE(e, d) \ + case e: \ + return d; + EXCEPTIONS(CASE) +#undef CASE + } +} +``` -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). +This technique can also be used to generate the function wrappers when using +the `WRAP` macro from [version 4](#version-4). ```cpp #define API(M) \ @@ -121,13 +175,14 @@ following is an example, using the `WRAP` macro from [version 4](#version-4). API(WRAP) ``` -To close this appendix with some words the same great hacker friend once said: +To conclude this appendix, let me share a quote from that same great hacker +friend: > *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 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]] |