我想这是代码风格和传统的问题,但问题如下。
假设我们有一个检查参数的函数,例如:
int do_something(int * arr) {
if (arr == NULL) {
printf("arr is NULLn");
return -1;
}
...
现在我们将使用它。问题是:我们应该检查我们将要传递给它的论点吗?因为它无论如何都会检查它。
该示例相当简单,现实生活中的场景可能要困难得多,调用函数会产生更多的参数(和更复杂的检查)和更多的额外开销 - 如果这是某种IPC。
因此,更普遍的问题是:关于这种情况,有哪些共同的准则和做法?
这将基于个人经验和偏见。无论如何,它在这里:
-
如果
do_something
属于库,并且作为可以直接调用的函数向库的用户公开,则最好进行任何和所有必要的检查以确保do_something
是健壮的。 -
如果它是库中的内部函数,最好还是进行任何和所有必要的检查,以确保
do_something
是健壮的。我会做而不进行检查的唯一例外是程序/库的性能是否受到检查的不利影响。 -
如果它是您自己的应用程序中的函数,则最好进行任何和所有必要的检查,以确保
do_something
是健壮的。我会做而不进行检查的唯一例外是程序/库的性能是否受到检查的不利影响。
如果函数被记录为检查参数,则调用它而不进行检查。例如,free()
被明确记录为接受NULL
作为参数,因此编写太常见的参数是没有意义的
if(p != NULL)
free(p);
它使您的代码混乱而没有任何好处。避免不必要的呼叫的收益通常完全在噪音中被拉出来。
当然,您必须检查函数的返回值。
如果您是函数的实现者,无论是库函数还是本地帮助程序函数,甚至可以在某些编译器上注释函数的特定协定。
例如,如果您的函数不接受 NULL
指针,则可以在函数声明时设置(在 gcc 上)__attribute__((nonnull))
。
例如,如果您声明:
int do_something(int * arr) __attribute__((nonnull (1)));
你会知道你不能用NULL
调用函数(如果编译器知道你这样做,它甚至会发出警告)。但要小心,这个属性可能会让人感到意外。如果您像我一样声明它,并且您仍然会像在示例中那样检查参数,那么您可能会发现优化器从目标代码中完全删除了检查。