Variadic heterogenous FREE macro

孤人 提交于 2020-01-14 01:37:38

问题


I want a macro to free multiple (variadic number) pointers of different type. Based on similar questions in SO I made this code which seems to work

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

/* your compiler may need to define i outside the loop */
#define FREE(ptr1, ...) do{\
    void *elems[] = {ptr1, __VA_ARGS__};\
    unsigned num = sizeof(elems) / sizeof(elems[0]);\
    for (unsigned i=0; i < num; ++i) free(elems[i]);\
} while(0)


int main(void) 
{
    double *x = malloc(sizeof(double)); /* your compiler may need a cast */
    int    *y = malloc(   sizeof(int)); /* ditto */

    FREE(x, y); 
}

My question is

  • Is the creation of a void* array correct in this context? (I saw the same trick with *int[], so the question is will a *void[] do what I expect)
  • Is the code C99 compliant, are there any compilers that would have problems with this?

回答1:


One potential usability problem with this is that it doesn't scale to freeing only a single pointer, similar to the regular free. While this isn't necessary (since you could require the user to spot this and use free), it's usually elegant for things to be as generic as possible and automatically scale themselves to fit such use cases.

C99 (also C11) standard section 6.10.3 paragraph 4:

If the identifier-list in the macro definition does not end with an ellipsis ... Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...).

i.e. in strictly conforming C, the __VA_ARGS__ must be used. GCC will even highlight this for you (a compiler can't prove something is compliant, but it can warn you when it isn't) when using -std=c99 -Wall -pedantic:

test.c: In function 'main':
test.c:18:11: warning: ISO C99 requires rest arguments to be used [enabled by default] FREE(x); ^

Technically you don't need the actual value, just the trailing comma (FREE(x,); - an empty macro argument is still an argument, and the array initializer it populates also allows trailing commas), but that's not very... integrated with the language.

In practice real compilers won't directly object to missing rest-args, but they might warn about it (as shown above), because a non-fatal error is often reasonable to interpret as a sign that something is wrong elsewhere.




回答2:


That's pretty cool, and yes it's correct to use void *.

You could improve it somewhat (more const, and of course use size_t instead of unsigned) but in general it seems alright.

Also, drop the casts in main(), there's no need to cast the return value of malloc() in C and doing so can mask actual errors so it's just bad.

To address @Leushenko's answer, you might be able to glue something together by adding an extra macro expansion step that always adds a NULL in the varargs macro call. That way, you're never going to call the actual varargs macro with just a single argument, even if the toplevel macro is called with only one. Of course, calling free(NULL) is always safe and well-defined, so that should work.



来源:https://stackoverflow.com/questions/28041370/variadic-heterogenous-free-macro

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!