Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Better then

#define ZFREE(p) do { free(p); p = NULL; } while(0)



You can even do

  #define free(p) do { free(p); p = NULL; } while(0)
And when you want to call the original free:

  (free)(p);
The preprocessor will not substitute this occurence of free.


C n00b here - why the `do {} while(0)`? Couldn't you just do something like `#define free(p) { free(p); p = NULL; }`?


Semi-experienced C user here, I believe the anonymous block is perfectly adequate here. No idea why they are wrapping it in a single instance do loop, unless they’re unaware of block scoping or I’m unaware of some UB here.


do {} while(0) is a common idiom for macros in C, because it consumes the trailing semicolon, which a bare {} block doesn't do.

    if(x) MACRO();
    else something();
expands to

    if(x) { ... }; // Error!
    else something();


Here's the actual macro I (sometimes) use:

    #define FREE(ptrptr) do { \
        __typeof__(ptrptr) const __x = (ptrptr); \
        free(*__x); *__x = NULL; \
    } while(0)
There might be a better way of doing it though. Also, __typeof__() obviously isn't standard C.

Edit to add: I've honestly been moving away from using a macro and just putting both statements on one line like in the OP. For something so simple, using a macro seems like overkill.


What's the benefit of that over nn3's version?


It'll only evaluate the pointer once. It's possible to make this a function though, that might be preferable


Good point. But it seems like it would require usage like this:

    int* p = malloc(sizeof(int));
    FREE(&p);
What if we instead define the macro like this:

    #define FREE(ptr) do { \
        __typeof__(ptr)* const __x = &(ptr); \
        free(*__x); *__x = NULL; \
    } while(0)
Then make usage slightly shorter, as well as more similar to free():

    int* p = malloc(sizeof(int));
    FREE(p);


Taking a pointer-to-pointer is intentional to make it clear that the pointer will be modified. That's actually the most important difference from nn3's version IMHO.


I tried making it a plain function at one point but ran into some weirdness around using void * * with certain arguments (const buffers?). You don't want to accept plain void * because it's too easy to pass a pointer instead of a pointer to a pointer. Using a macro is (ironically) more type safe.

Maybe someone else could figure out how to do it properly, since I'd definitely prefer a function.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: