https://gustedt.wordpress.com/2025/01/06/simple-defer-ready-to-use/ Skip to content Jens Gustedt's Blog Simple defer, ready to use With this post I will concentrate on the here and now: how to use C's future lifesaving defer feature with existing tools and compilers. I have already talked several times about defer, the new feature that hopefully will make it into a future version of C. With this post I will concentrate on the here and now: how to apply that lifesaving feature with existing tools and compilers. After briefly discussing the defer feature itself, again, I will show you a first implementation with gcc extensions, a second with C++ standard features and then I will discuss a new proposal with for defer that has a syntax that is a tiny bit more constraining than what you may have seen so far. The defer feature itself To remind you what defer is supposed to do, here is some toy code that uses three resources: { // anchor block void* p = malloc(25); defer { free(p); }; // 1st defer mtx_lock(&mut); defer { mtx_unlock(&mut); }; // 2nd defer static uint64_t critical = 0; critical++; defer { critical--; }; // 3rd defer while (something) cnd_wait(&cond, &mut); ... use p under protection of mut ... } This code with three so-called deferred blocks is equivalent to the following { void* p = malloc(25); mtx_lock(&mut); static uint64_t critical = 0; critical++; while (something) cnd_wait(&cond, &mut); ... use p under protection of mut ... { critical--; } // from 3rd defer { mtx_unlock(&mut); } // from 2nd defer { free(p); } // from 1st defer } only that the deferred blocks are even executed when the anchor block is left by a jump statement (such as a break, continue, return or even goto) that would be nested inside complicated if/else conditionals. Thus using defer here ensures that * p, something and critical are only used under the protection of the mutex mut, * critical then holds the number of threads that are currently within that anchor block * mut never remains locked whenever the anchor block is left. * *p is deallocated whenever the anchor block is left. Implementing defer with gcc With a minimal macro wrapper this feature works out of the box in gcc since at least two decades. Written with C23's attribute feature the inner macro looks as simple as the following: #define __DEFER__(F, V) \ auto void F(int*); \ [[gnu::cleanup(F)]] int V; \ auto void F(int*) Here the three lines of the macro are as follows: * auto void F(int*); forward-declares a nested (local) function F. * [[gnu::cleanup(F)]] int V; establishes this function as a cleanup handler of an auxiliary variable V * The second auto void F(int*) then starts the definition of the local function which is completed with the user's compound statement as the function body. For this to work we have to provide unique names F and V such that several defer blocks may appear within the same anchor block. This is ensured by another very common extension __COUNTER__ #define defer __DEFER(__COUNTER__) #define __DEFER(N) __DEFER_(N) #define __DEFER_(N) __DEFER__(__DEFER_FUNCTION_ ## N, __DEFER_VARIABLE_ ## N) That is basically it, a straight application of the [[gnu::cleanup]] feature that * avoids the need for inventing safe identifiers, * avoids the definition of an one-shot function with internal or external linkage far away from its use, * integrates well and quite efficiently with the existing compiler infrastructure. Indeed, when adding a bit more magic (such as [[gnu::always_inline]]) the assembly that is produced is very efficient and avoids function calls, trampolines and indirections. (See also Omar Anson's blog entry on how efficient the cleanup attribute seems to be implemented in gcc.) If you don't like or have the C23 attribute syntax yet, you should easily be able to use gcc's legacy __attribute__((...)) syntax without problems. Implementing defer with C++ Yes! I think it would even make sense for C++, but what do I know. At least the following implementation shows that the feature fits directly into C++'s model of binding actions to a scope. In fact, implementing the defer feature with the properties as desired in C++ is a student excercise. It can be done with a template class and lambdas. template struct __df_st : T { [[gnu::always_inline]] inline __df_st(T g) : T(g) { // empty } [[gnu::always_inline]] inline ~__df_st() { T::operator()(); } }; #define __DEFER__(V) __df_st const V = [&](void)->void Lambda expressions have a unique type for each expression. Such a lambda expression is taken here as a template parameter to the constructor __df_st::__df_st(T). The destructor __df_st ::~__df_st() of the variable then invokes the lambda when V leaves its scope. The [&] in [&](void)->void { some code } ensures that all outer variables are fully accessible at the point of execution of the lambda. Therefore, such an implementation provides the full functionality that we need for our first example from above. Note, that the __COUNTER__ pseudo-macro is also quite commonly implemented by C++ compilers and is now even proposed as an addition to C++26. Thus with a similar macro as for gcc above we can implement the defer macro itself: #define defer __DEFER(__COUNTER__) #define __DEFER(N) __DEFER_(N) #define __DEFER_(N) __DEFER__(__DEFER_VARIABLE_ ## N) A note on the syntax for defer As we have seen above existing implementations (let's also count the one for C++) use quite different features under the hood: One uses a function declaration where a compound statement of the user code as in defer { mtx_unlock(&mut); }; ends up being a function body. Here the terminating ; is superfluous, but doesn't hurt much, either. The other declares a expression that also needs {} to limit the user code and a terminating ; because underneath it is an object declaration. I think we should combine these different syntax requirements, such that implementors (or library providers) may easily start providing this feature with what they have. I have recently made a new proposal to the C standards committee in that sense: Even simpler defer for direct integration, N3434 It has the advantage, I think, that it is much easier and more direct that previous proposals and that it combines the possibility of implementing the feature in the language or in the library. Therefore the defer features is proposed as a "block item" in a compound statement (its anchor) and then defined via the syntax rules defer-block: defer deferred-block ; deferred-block: compound-statement Share this: * Share * * Email * Print * Facebook * Twitter * Related [1852c]Author Jens GustedtPosted on January 6, 2025Categories C23, C2x, macrosTags define Post navigation Previous Previous post: The C23 edition of Modern C [1852c43e] Mastodon C as a language [dotd_newmeap_gustedt21-1] Copyright (c) 2010-2024 Jens Gustedt, Strasbourg, France eLlipsis a language independent preprocessor P99 macros for C99 emulation of C11 Categories * C++ (10) * C11 (45) + defects (11) + feature request (2) + library (9) * C17 (11) * C2x (25) + C23 (18) * C99 (77) + integers (13) + language (34) + P99 (17) + preprocessor (16) + syntax (17) * compiler optimization (5) * core (3) * eLlipsis (3) * fediverse (1) * lock structures (8) * macros (3) * Modern C (3) * Modular C (5) * POSIX (14) + linux (3) * rants (5) * Uncategorized (1) Recent Posts * Simple defer, ready to use * The C23 edition of Modern C * Braiding the spaghetti: implementing defer in the preprocessor * Tail recursion for macros in C * ELlipsis: a language independent preprocessor is released Top Posts & Pages * Simple defer, ready to use * Braiding the spaghetti: implementing defer in the preprocessor * The C23 edition of Modern C * A defer mechanism for C * Myth and reality about inline in C99 * Modern C, Second Edition * Detect empty macro arguments * flexible array member * A defer feature using lambda expressions * Tail recursion for macros in C Search for: [ ] Search related * C99 * c threads * define * elif * endif * preprocessor * undef Follow Blog via Email Enter your email address to follow this blog and receive notifications of new posts by email. Email Address: [ ] Follow Join 209 other subscribers Meta * Register * Log in * Entries feed * Comments feed * WordPress.com Archives * January 2025 * October 2024 * September 2024 * July 2024 * June 2024 * May 2024 * February 2024 * January 2024 * December 2023 * October 2023 * August 2023 * June 2023 * December 2022 * January 2022 * October 2021 * January 2021 * December 2020 * November 2020 * June 2020 * May 2020 * March 2020 * September 2019 * August 2018 * June 2018 * April 2018 * August 2017 * May 2017 * March 2017 * January 2017 * November 2016 * September 2016 * August 2016 * July 2016 * July 2015 * May 2015 * April 2015 * February 2015 * October 2014 * September 2014 * April 2014 * December 2013 * October 2013 * August 2013 * July 2013 * February 2013 * December 2012 * November 2012 * October 2012 * August 2012 * July 2012 * May 2012 * April 2012 * March 2012 * February 2012 * January 2012 * December 2011 * November 2011 * October 2011 * July 2011 * June 2011 * March 2011 * February 2011 * January 2011 * December 2010 * November 2010 * October 2010 * September 2010 * August 2010 * July 2010 * June 2010 RSS RSS Feed RSS - Posts RSS Feed RSS - Comments Jens Gustedt's Blog Create a free website or blog at WordPress.com. [Close and accept] Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use. To find out more, including how to control cookies, see here: Cookie Policy * Subscribe Subscribed + [wpcom-] Jens Gustedt's Blog Join 209 other subscribers [ ] Sign me up + Already have a WordPress.com account? Log in now. * + [wpcom-] Jens Gustedt's Blog + Customize + Subscribe Subscribed + Sign up + Log in + Copy shortlink + Report this content + View post in Reader + Manage subscriptions + Collapse this bar [b] Design a site like this with WordPress.com Get started