我有这个宏:
/*
* 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_); \
} \
)
,我希望它能够提高安全性。这是第一个想法:
#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;
}
但是随后编译器抱怨:
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 **
对(void **)
进行安全的简单显式转换是吗?:
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
\
callocs__((void **)ptr_, nmemb, sizeof(**ptr_)); \
} \
)
从安全的角度来看,我既是指标准的观点(我想不是),也指实现的观点(在这种情况下为GNU C)(我不确定)。
如果不是,那么void *
类型的中间指针就足够了吗?:
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
void *vp_; \
int ret_; \
\
ret_ = callocs__(&vp_, nmemb, sizeof(**ptr_)) \
*ptr_ = vp_; \
ret_; \
} \
)
还有其他解决方法吗?
答案 0 :(得分:1)
是否将简单的显式强制转换为(void **)安全?:
如果不是这样,那么void *类型的中间指针就足够了吗?:
(void **)
方法是合理的,但依赖于some_other_type **
与void **
兼容。它属于:
指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未针对引用类型正确对齐,则该行为未定义。否则,当再次转换回时,结果应等于原始指针。 C17dr§6.3.2.2 7
因此,在一种罕见的情况下,指向一种类型的指针与指向void *
的指针具有不同的对齐要求。我怀疑这样的实现是否存在。需要明确的是,这是指针类型(而不是它们指向的对象)对齐要求的区别。
还有其他解决方法吗?
为避免“从不兼容的指针类型传递callocs__的参数1”并保持类型正确性,请考虑使辅助函数callocs__()
为
void *callocs__(ptrdiff_t nmemb, size_t size, int *error);
// ^------------return pointer to allocated data
然后
#define callocs(ptr, nmemb) ( \
{ \
__auto_type ptr_ = (ptr); \
int error; \
*ptr = callocs__(nmemb, sizeof(**ptr_), &error); \
error; \
} \
)
注意:我赞扬制作一个函数来处理*alloc()
中微妙的vagaries的总体目标。