From ed41c1ddd9d590165277c756f4498948490265ac Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Sun, 28 Apr 2024 20:39:24 +0200 Subject: fn-wrapper: CONCAT1 vs CONCAT2, re-wording, additional listify example --- content/2024-04-24-fn-wrapper-macro-magic/index.md | 93 +++++++++++++++++----- 1 file changed, 72 insertions(+), 21 deletions(-) (limited to 'content/2024-04-24-fn-wrapper-macro-magic') 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 b966a1a..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 @@ -105,16 +103,68 @@ variadic argument list [__VA_ARGS__][va-args] is presented in > 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) \ @@ -125,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]] -- cgit v1.2.3