aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--content/2024-04-24-fn-wrapper-macro-magic/index.md93
1 files changed, 72 insertions, 21 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 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]]