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:

  1. We define a DeferredCall structure to hold a function pointer and its argument.

  2. We use a global array deferredCalls to store these deferred calls.

  3. The defer function adds a new deferred call to this array.

  4. The runDeferred function executes all deferred calls in reverse order (last-in-first-out).

  5. In the main function, we use this mechanism to defer the closing of the file.

To run the program:

$ gcc defer.c -o defer
$ ./defer
creating
writing
closing

This 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.