← Back to davo.co
aboutsummaryrefslogtreecommitdiffstats
path: root/anonymous_function.c
diff options
context:
space:
mode:
authorDavid Faulkner <[email protected]>2026-08-07 23:40:47 -0500
committerDavid Faulkner <[email protected]>2026-08-07 23:40:47 -0500
commitb3e9e62599532050fc776c5e8f076915b56c2235 (patch)
treeaf252346106a61b18cc6fc6fdbd32e962d096f1c /anonymous_function.c
Import official C23 code examples for Modern C (Jens Gustedt, 2024)HEADupstream-importmain
- Add official C source files, Makefile, c23-fallback.h, and LICENSE - Update README.md with study mirror notice
Diffstat (limited to 'anonymous_function.c')
-rw-r--r--anonymous_function.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/anonymous_function.c b/anonymous_function.c
new file mode 100644
index 0000000..8144e6f
--- /dev/null
+++ b/anonymous_function.c
@@ -0,0 +1,96 @@
+#include <stdio.h>
+
+/**
+ ** @file
+ **
+ ** This plays with gcc features to define a weird macro that emulates
+ ** anonymous functions that can be used as closures. Don't use that
+ ** seriously, this is only meant to prove that this is syntactically
+ ** not a big deal, and that the ideas necessary for it can be found
+ ** in modern compilers.
+ **
+ **/
+
+/**
+ ** @def ANONYMOUS(RET)
+ ** @brief Use this to define an anonymous function with return type @a RET.
+ **
+ ** The @c ... argument list is the parameter list of the
+ ** function. This the expects the code of the function in <code>({
+ ** })</code> parenthesis. A simple example would be
+ **
+ ** @code
+ ** // Function header
+ ** ANONYMOUS(int) (double a, unsigned b)
+ ** // Function body
+ ** ({
+ ** return printf("we found %g for %u, average %g\n", a, b, a/b);
+ ** })
+ ** // Function arguments
+ ** (x, 23);
+ ** @endcode
+ **
+ ** Of course you would usually put such things inside a macro. See
+ ** MAX() for a more complicated example.
+ **/
+#ifdef __clang__
+# define ANONYMOUS(RET) (^ RET ANON_PART2
+# define ANON_PART2(...) (__VA_ARGS__) ANON_PART3
+# define ANON_PART3(...) __VA_ARGS__)
+#else
+# define ANONYMOUS(RET) ({ RET __anon_func ANON_PART2
+# define ANON_PART2(...) (__VA_ARGS__) ANON_PART3
+# define ANON_PART3(...) __VA_ARGS__ __anon_func; })
+#endif
+
+#define MAXU(A, B) \
+ANONYMOUS(uintmax_t) (uintmax_t a, uintmax_t b) \
+({ \
+ if (a < b) return b; \
+ else return a; \
+}) \
+((A), (B))
+
+#define MAX(A, B) \
+/* function header */ \
+ /* return type */ \
+ANONYMOUS(__typeof__(1 ? (A) : (B))) \
+ /*and then argument list */ \
+(__typeof__(A) a, __typeof__(B) b) \
+/* function body */ \
+({ \
+ if (a < b) return b; \
+ else return a; \
+ }) \
+/* function call */ \
+((A), (B))
+
+/**
+ ** Test to see if that even works when such functions are nested.
+ **/
+
+typedef void df(unsigned);
+
+df* Df[5] = { };
+
+void g(unsigned level, unsigned depth) {
+ Df[depth%5] =
+ ANONYMOUS(void) (register unsigned a)
+ ({
+ printf("from level %u, depth %u found in position %u\n",
+ level, depth,
+ MAX(2*a, depth)
+ );
+ return;
+ });
+ if (level)
+ g(level-1, depth+1);
+ else
+ for (unsigned i = 0; i < 5; ++i)
+ if (Df[i]) Df[i](i);
+}
+
+
+int main(int argc, [[maybe_unused]] char* argv[]) {
+ g(argc, 0);
+}