Variadic异质FREE宏

我想要一个宏来释放不同类型的多个(可变数字)指针。 基于SO中的类似问题,我制作了这个代码似乎有效

#include  #include  #include  /* 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); } 

我的问题是

  • 在这种情况下, void*数组的创建是否正确? (我在*int[]看到了相同的技巧,所以问题是*void[]做我期望的事情)
  • 代码C99是否兼容,是否有任何编译器会遇到此问题?

一个潜在的可用性问题是它不能扩展到只释放一个指针,类似于常规的free 。 虽然这不是必需的(因为您可能要求用户发现并free使用),但通常优雅的是尽可能通用并自动扩展以适应此类用例。

C99 (也是C11 )标准第6.10.3段第4段:

如果宏定义中的标识符列表没有以省略号结尾…否则,调用中的参数应该多于宏定义中的参数(不包括... )。

即在严格符合C的情况下,必须使用__VA_ARGS__ 。 当使用-std=c99 -Wall -pedantic时,GCC甚至会为你强调这一点(编译器无法certificate某些东西合规的,但它可以警告你什么时候没有):

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

从技术上讲,你不需要实际值,只需要尾随逗号( FREE(x,); – 一个空的宏参数仍然是一个参数,它填充的数组初始化程序也允许尾随逗号),但这不是很…与语言融为一体。

在实践中,真正的编译器不会直接反对丢失的rest-args,但是他们可能会警告它(如上所示),因为非致命错误通常是合理的,可以解释为其他地方出现问题的迹象。

这很酷,是的,使用void *是正确的。

你可以稍微改进它(更常见,当然使用size_t而不是unsigned )但总的来说它似乎没问题。

另外,在main()删除强制转换, 不需要在C中强制转换malloc()的返回值,这样做可以掩盖实际错误,所以它很糟糕。

为了解决@ Leushenko的答案 ,您可以通过添加额外的宏扩展步骤来粘合一些东西,该步骤总是在varargs宏调用中添加NULL。 这样,即使只用一个参数调用顶层宏,你也永远不会用一个参数调用实际的varargs宏。 当然,调用free(NULL)总是安全且定义良好的,所以应该可行。