通过指针分配给指针参数

时间:2019-12-30 19:16:27

标签: c pointers gcc malloc void-pointers

我有这个宏:


/*
 * 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_;                                                           \
}                                                                       \
)

还有其他解决方法吗?

1 个答案:

答案 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的总体目标。