库层次结构中的参数检查

时间:2013-08-29 21:44:33

标签: c parameters parent-child

在编写函数库时,如果已经在父库中检查了函数参数是否应在子库中检查,是否存在共识?举例来说,请考虑以下代码片段:

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()中的检查的依赖。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

这取决于库函数。

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

库内部的函数,仅由库中的函数调用的函数,不需要对其参数进行额外的检查 - 除非存在只有该函数可以检查的条件。网关(接口)函数应该验证它们的参数,因此内部函数不需要重新验证它们。您可能仍然使用断言检查内部函数,因此如果函数错误地调用其中一个内部函数,则在开发期间发现这一点。但是那些断言应该永远很少发火。

答案 1 :(得分: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;
}

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

另一个好处是,每次调用er_removede_remove_first时,调用者都不必检查此参数,从而简化了代码。如果free是这样设计的,该怎么办?想一想。

// Check NULL whenever you call free to release a piece of memory
if (ptr != NULL)
{
   free(ptr);
}