Skip to content

Instantly share code, notes, and snippets.

@louy2
Last active March 31, 2016 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save louy2/ce750f2e5af38432a06db78c7e89f3c0 to your computer and use it in GitHub Desktop.
Save louy2/ce750f2e5af38432a06db78c7e89f3c0 to your computer and use it in GitHub Desktop.
`defer` from Go (Golang) to C -- in [Emulating "defer" in C, with Clang or GCC+Blocks](http://fdiv.net/2015/10/08/emulating-defer-c-clang-or-gccblocks) by [smokris](http://fdiv.net/users/smokris)
static inline void defer_cleanup(void (^*b)(void)) { (*b)(); }
#define defer_merge(a,b) a##b
#define defer_varname(a) defer_merge(defer_scopevar_, a)
#define defer __attribute__((cleanup(defer_cleanup))) void (^defer_varname(__COUNTER__))(void) =

How does the magic work? Starting from the last line:

  1. __attribute__((cleanup(…))) — an extension to the C language, provided by GCC and Clang. When a variable is tagged with this attribute, the specified function is invoked when the variable leaves scope.
  2. void (^…)(void) = ^{ … } — C Blocks, an extension to the C language, provided by Clang or GCC with Apple’s Blocks patch. Allows you to define inline, anonymous functions. In this case, I’m taking the block that’s expected to appear after the defer macro and assigning it to a local variable.
  3. a##b — merge two strings into a single token. By combining defer_scopevar_ with the __COUNTER__, I get a unique variable name.
  4. void defer_cleanup(void (^*b)(void)) { (*b)(); } — a C function that takes a block as its parameter. I pass this function to __attribute__((cleanup(…))), and it gets invoked when the variable (defined in step #2) leaves scope. When the function is invoked, it just calls the block that was passed to it. (This indirection is necessary since __attribute__((cleanup(…))) doesn’t directly support C Blocks.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment