I have this macro:
/*
* int callocs(type **ptr, size_t nmemb);
*
* Safe & simple wrapper for `calloc()`.
*
* PARAMETERS:
* ptr: Memory will be allocated, and a pointer to it will be stored
* in *ptr.
* nmemb: Number of elements in the array.
*
* RETURN:
* 0: OK.
* != 0: Failed.
*
* FEATURES:
* - Safely computes the element size (second argument to `calloc()`).
* - Returns non-zero on error.
* - Doesn't cast.
* - The pointer stored in `*ptr` is always a valid pointer or NULL.
*
* EXAMPLE:
* #define ALX_NO_PREFIX
* #include <libalx/base/stdlib/alloc/callocs.h>
*
* int *arr;
*
* if (callocs(&arr, 7)) // int arr[7];
* goto err;
*
* // `arr` has been succesfully allocated here
* free(arr);
* err:
* // No memory leaks
*/
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
\
*ptr_ = calloc(nmemb, sizeof(**ptr_)); \
\
!(*ptr_); \
} \
)
and I would like it to be a function to improve safety. This would be the first idea:
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
\
callocs__(ptr_, nmemb, sizeof(**ptr_)); \
} \
)
int callocs__(void **ptr, ptrdiff_t nmemb, size_t size)
{
if (nmemb < 0)
goto ovf;
*ptr = calloc(nmemb, size);
return !*ptr;
ovf:
errno = ENOMEM;
*ptr = NULL;
return ENOMEM;
}
But then the compiler complains with:
error: passing argument 1 of callocs__ from incompatible pointer type [-Werror=incompatible-pointer-types]
note: in expansion of macro callocs
note: expected void ** but argument is of type struct My_Struct **
Is a simple explicit cast to (void **)
safe?:
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
\
callocs__((void **)ptr_, nmemb, sizeof(**ptr_)); \
} \
)
By safe I mean both from the Standard point of view (which I guess is not) and from implementations point of view (in this specific case, GNU C) (which I'm not sure).
And if not, would an intermediate pointer of type void *
be enough?:
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
void *vp_; \
int ret_; \
\
ret_ = callocs__(&vp_, nmemb, sizeof(**ptr_)) \
*ptr_ = vp_; \
ret_; \
} \
)
Is there any other solution?