I wonder if this can be emulated with for loop:
for(FILE *fp = fopen(path, "wb");
fp != NULL;
fclose(fp), fp = NULL) {
...
} for(FILE *fp = fopen(path, "wb");
fp != NULL;
fclose(fp), fp = NULL) {
...
}If you are interested, I did provide a few macros[2], but as another commenter pointed out, they won't handle an early return. You can use "break" to exit early though:
#define with(declare, startup, cleanup, block) \
{ \
declare; \
if (( startup )) { \
do { \
block; \
} while(0); \
cleanup; \
} \
}
with (FILE *fp, fp = fopen(path, "rb"), fclose(fp), {
fread(buf, 1, sizeof(buf)-1, fp);
if (ferror(fp)) {
perror(path);
break;
}
printf("%s\n", buf);
success = 1;
})
There's also "withif" #define withif(declare, startup, cleanup, block, otherwise) \
{ \
declare; \
if (( startup )) { \
do { \
block; \
} while(0); \
cleanup; \
} otherwise; \
}
[1]https://github.com/taeber/cwithHere is a macro that can be used to emulate a defer
#define CONCAT_(a, b) a ## b
#define CONCAT(a, b) CONCAT_(a, b)
#define UNIQUENAME() CONCAT(i_, __LINE__)
#define SCOPE_(counter, init_stmt, exit_stmt) for (int counter = ((init_stmt), 1); counter--; (exit_stmt))
#define SCOPE(init_stmt, exit_stmt) SCOPE_(UNIQUENAME(), (init_stmt), (exit_stmt))
Granted it's a hack, but it can be useful at times. I've used something like it to define a large data hierarchy in code for example, as having to close all the nodes manually is tedious.You could wrap a second for-loop around the definition of the macro to at least be able to catch misplaced "break" statements.
SCOPE(Resource *ptr = acquire_resource(),
release_resource(ptr))
{
// do stuff with resource ptr.
}
Actually, to allow variable declarations in the init_stmt like above, you'll need to use two nested for-loops: #define SCOPE_(name, begin_stmt, end_stmt) for (int name = 0; !name; assert(name && "should never break from a SCOPE")) for (begin_stmt; !name; name++, (end_stmt))
It is natural to add another layer of specific usage macro like this: #define UI_NODE(ctx) SCOPE(push_ui_node(ctx), pop_ui_node(ctx))
UI_NODE(ctx)
{
ui_color(ctx, UI_COLOR_RED);
const char *items[3] = { "a", "b", "c" };
for (int i = 0; i < 3; i++)
{
UI_NODE(ctx)
ui_text(ctx, items[i]);
}
}
Naturally, if you're already on C++, better code these macros in terms of RAII instead of abusing for-loops. That will add a little robustness.