2

在编写函数库时,如果函数参数已经在父库中被检查,是否应该在子库中检查函数参数是否有共识?作为说明,请考虑以下代码片段:

uint8 er_remove(DE_LIST *deque)
{
    ER_OBJECT *object;
    uint8 result = ER_BAD_ARGUMENT;

    if (deque != NULL)
    {
        result = de_remove_first(deque, (void **)&object);
    }

    return result;
}

鉴于该函数de_remove_first()还检查deque参数以查看它是否为 NULL,在 中再次检查它是否被认为是好的形式er_remove()

从功能的角度来看,签到er_remove()显然是没有必要的。然而,它确实让读者清楚地看到deque参数被检查,并且它还消除了对de_remove_first()在未来代码修订中保留的检查的依赖。

有什么想法吗?

4

2 回答 2

2

这取决于库函数。

作为库的外部接口的一部分记录的所有函数——用户调用的函数——应该严格验证他们的参数(或者至少考虑这样做)。

库内部的函数,仅由库中的函数调用的函数,不需要对其参数进行额外的检查——除非存在只有该函数才能检查的条件。网关(接口)函数应该已经验证了它们的参数,所以内部函数不需要重新验证它们。您可能仍会使用断言检查内部函数,以便如果函数错误调用其中一个内部函数,您可以在开发过程中发现这一点。但这些断言永远不应该很少触发。

于 2013-08-30T00:28:43.623 回答
0

不,你没有。

er_remove只是将该参数传递给另一个函数。在您的情况下,使用的逻辑deque完全在内部实现de_remove_first,唯一有责任进行检查的人。

如果在 中再次执行此操作,则de_remove_first会使两个函数都绑定到该参数的值。听起来有点矫枉过正。如果将来,de_remove_first经过优化并且可以接受 NULL 指针,会发生er_removed什么?

uint8 er_remove(DE_LIST *deque)
{
    ER_OBJECT *object;
    uint8 result = ER_BAD_ARGUMENT;

    // Will you remember to remove this kind of checks?
    if (deque != NULL)
    {
         // OK, I am now acceptable to a NULL "deque".
         result = de_remove_first(deque, (void **)&object);
    }

    return result;
}

最好的情况是它提醒你这个额外的检查。您会在调用路径中找到所有此类检查,并将它们删除。最糟糕的是您忘记更新它,并且接受 NULL 参数的代码de_remove_first只是被绕过并且永远不会被执行。

另一个好处是你的调用者不必在每次调用er_removeor时检查这个参数de_remove_first,从而简化了他们的代码。如果free是这样设计的呢?想想看。

// Check NULL whenever you call free to release a piece of memory
if (ptr != NULL)
{
   free(ptr);
}
于 2013-08-29T23:45:56.230 回答