Last active
March 8, 2025 09:31
-
-
Save DBJDBJ/c1dc33cc6df2e14f5d8840445f65f5ee to your computer and use it in GitHub Desktop.
Defer and Begin/End. For any C version. With Gobolt demo and proof of concept.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef DBJ_DEFER_BEGIN_END_H | |
#define DBJ_DEFER_BEGIN_END_H | |
/* | |
comment this in to see the demo | |
#define DBJ_DEFER_BEGIN_END_DEMO 1 | |
*/ | |
/* | |
2025-MAR [email protected] https://godbolt.org/z/adYP4ach4 | |
first seen it here https://youtu.be/QpAhX-gsHMs | |
2021-APR [email protected] added macro defer() | |
Two Macros. Usage: | |
beginend( on_scope_begin(), on_scope_end() ) { } | |
defer( on_scope_end() ) { } | |
See the ad-hoc-demo bellow | |
Q: What might be good about this two macros? | |
A: They work on any C version, using any compiler. | |
There is no trick: Both macros are for(){ } loop that loops once | |
I see no reason for this not to work on any C version and compiler | |
*/ | |
#define _POSIX_C_SOURCE 200112L | |
#include <stdlib.h> | |
#undef macro_concat_ | |
#undef macro_concat | |
#undef macro_var | |
#define macro_concat_(a,b) a ## b | |
#define macro_concat(a,b) macro_concat_(a,b) | |
#define macro_var(name) macro_concat( name, __LINE__) | |
#define beginend( start,end) \ | |
for ( int macro_var(_i_) = ( start, 0 ) ; ! macro_var(_i_) ; ( macro_var(_i_) += 1, end) ) | |
static inline void do_nothing_ (void) {} | |
// #define defer( at_scope_end ) beginend( __LINE__, at_scope_end ) | |
#define defer( at_scope_end) for ( int macro_var(_i_) = 0;\ | |
! macro_var(_i_) ; ( macro_var(_i_) += 1, at_scope_end) ) | |
#endif // DBJ_DEFER_BEGIN_END_H | |
/* | |
Ad-hoc demo | |
*/ | |
#if DBJ_DEFER_BEGIN_END_DEMO | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#undef B | |
#undef P | |
#undef M | |
// NOTE: F must be a string literal | |
#define B(X_) (X_) ? "true" : "false" | |
#define P(F,X_) fprintf( stdout, "\n%04d : %16s :\t" F, __LINE__, #X_, (X_)) | |
#define M(S) fprintf( stdout, "\n%04d : %16s :\t%s", __LINE__, " ", S) | |
static void make_ ( char ** ptr, size_t sze_ ) { *ptr= (char*)calloc(sze_, sizeof(char)); P("made (%p)", (void*)*ptr); P("char [%zu]", sze_); } | |
static void free_ ( void * ptr ) {P("freed (%p)", ptr ); free(ptr); ptr = NULL; } | |
static void close_file ( FILE * fp_ ) { | |
if ( fp_ == NULL) { M("close_file(): Avoiding NULL file pointer"); | |
return ; } | |
if ( ferror(fp_)) perror("I/O error"); | |
P("closing FILE * (%p)", (void*)fp_); | |
fclose(fp_ ) ; | |
} | |
static void here_ (void) { M("for() {} block Begin"); } | |
static void there_ (void) { M("for() {} block End"); } | |
int main (void) | |
{ | |
M("Very simmple demo -----------------------------------"); | |
beginend( here_(), there_() ) | |
{ | |
M("Inside for(){} block"); | |
} | |
char * bufy_ = 0 ; | |
printf("\n"); | |
M("Mandatory auto free demo ----------------------------"); | |
beginend( make_( &bufy_, 0xFF ), free_( bufy_ ) ) | |
{ | |
memcpy( bufy_, "DATA", 5 ); | |
P("using (%p)", (void*)bufy_); P("\"%s\"", bufy_); | |
} | |
printf("\n"); | |
M("Defer file close demo -------------------------------"); | |
FILE * dummsy_ = tmpfile(); | |
defer( close_file( dummsy_ )) { | |
P("temp FILE * (%p)", (void*)dummsy_); | |
} | |
return 42 ; | |
} | |
#undef B | |
#undef P | |
#undef M | |
#endif // DBJ_DEFER_BEGIN_END_DEMO | |
gcc 10.3: https://godbolt.org/z/3dWKdsadr
gcc 14.2 also OK
args for both: -s -Wall -pedantic
Ah yes, this does not work for GCC 14.2 C++ , or clang 19.1.0?
39 | for ( int macro_var(i) ... error: 'i' was not declared in this scope
strange, macro expansion rules may have changed.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Once more: arguments are function calls. But: not executed because they are macro arguments.
That is because
beginend
is a macro, not a function. And macro is just a text replacement mechanism. Ditto, the above is translated into this:Notice the comma operators in the for() above 😉