Defer in C
In C, there’s no direct equivalent to the defer keyword. However, we can achieve similar functionality using function pointers and a custom cleanup mechanism. Here’s how we could implement a similar concept:
#include <stdio.h>
#include <stdlib.h>
#define MAX_DEFERRED 10
typedef struct {
void (*func)(void*);
void* arg;
} DeferredCall;
DeferredCall deferredCalls[MAX_DEFERRED];
int deferredCount = 0;
void defer(void (*func)(void*), void* arg) {
if (deferredCount < MAX_DEFERRED) {
deferredCalls[deferredCount].func = func;
deferredCalls[deferredCount].arg = arg;
deferredCount++;
}
}
void runDeferred() {
for (int i = deferredCount - 1; i >= 0; i--) {
deferredCalls[i].func(deferredCalls[i].arg);
}
deferredCount = 0;
}
void closeFile(void* arg) {
FILE* f = (FILE*)arg;
printf("closing\n");
if (fclose(f) != 0) {
fprintf(stderr, "error: failed to close file\n");
exit(1);
}
}
FILE* createFile(const char* p) {
printf("creating\n");
FILE* f = fopen(p, "w");
if (f == NULL) {
perror("Error creating file");
exit(1);
}
return f;
}
void writeFile(FILE* f) {
printf("writing\n");
fprintf(f, "data\n");
}
int main() {
FILE* f = createFile("/tmp/defer.txt");
defer(closeFile, f);
writeFile(f);
runDeferred();
return 0;
}In this C implementation, we’ve created a simple deferred execution mechanism:
We define a
DeferredCallstructure to hold a function pointer and its argument.We use a global array
deferredCallsto store these deferred calls.The
deferfunction adds a new deferred call to this array.The
runDeferredfunction executes all deferred calls in reverse order (last-in-first-out).In the
mainfunction, we use this mechanism to defer the closing of the file.
To run the program:
$ gcc defer.c -o defer
$ ./defer
creating
writing
closingThis implementation mimics the behavior of the original example. The file is created, written to, and then closed as the last operation, even though the closeFile function is “deferred” earlier in the code.
Note that this is a simplified implementation and doesn’t handle all edge cases. In production code, you’d want to add more error checking and possibly use dynamic allocation for the deferred calls array.
Also, it’s important to remember that in C, manual memory management is crucial. Always ensure that resources are properly freed, whether using a deferred execution mechanism or not.