C 库层次结构中的参数检查

C 库层次结构中的参数检查,c,parameters,parent-child,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)

在编写函数库时,如果函数参数已经在父函数库中检查过,那么是否应该在子函数库中检查它们,是否存在共识?通过说明,考虑下面的代码片段:

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()
在将来的代码修订中保持不变的依赖

有什么想法吗?

不,你没有

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

如果在
de_remove_first
中再次执行此操作,则会使两个函数都绑定到该参数的值。听起来有点过分了。如果将来,
de_remove_first
经过优化,可以接受空指针,那么
er_remove
会发生什么情况

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
中接受空参数的代码被绕过,永远不会执行

另一个好处是,调用方不必每次调用
er\u remove
de\u remove\u first
时都检查此参数,从而简化了代码。如果
free
是这样设计的呢?想想看

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

这取决于库的功能

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


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

一般来说,需要条件的函数是验证它的地方。请看先决条件、后置条件和不变量。它们不是我以前遇到过的概念-谢谢。这听起来是一种非常明智的方法。非常感谢。