28

许多 C 代码释放指针调用:

if (p)
  free(p);

但为什么?我认为 C 标准说该free函数在给定 NULL 指针的情况下不做任何事情。那么为什么要进行另一个明确的检查呢?

4

8 回答 8

26

构造:

free(NULL);

在 C 语言中一直没问题,回到 Dennis Ritchie 编写的原始 UNIX 编译器。预标准化,一些糟糕的编译器可能没有正确使用它,但是现在任何编译器都不能合法地称自己为 C 语言的编译器。使用它通常会导致更清晰、更易于维护的代码。

于 2009-12-16T12:01:59.933 回答
17

据我了解,NULL 上的无操作并不总是存在。

在 C 的糟糕旧时代(早在 1986 年左右,在 ANSI 标准之前的 cc 编译器上)free(NULL) 会转储核心。所以大多数开发人员在免费调用之前测试了 NULL/0。

世界已经走了很长一段路,看来我们不再需要进行测试了。但是旧习惯很难改掉;)

http://discuss.joelonsoftware.com/default.asp?design.4.194233.15

于 2009-12-16T04:42:26.860 回答
10

我倾向于写if (p) free(p)很多“”,即使我知道它没有必要。

我部分责备自己,因为我在过去学习 C 时free(NULL)会出现段错误,但不这样做我仍然感到不舒服。

但我也指责 C 标准不一致。例如, fclose(NULL) 是否定义明确,我在写作时不会有问题:

free(p);
fclose(f);

这是清理东西时经常发生的事情。不幸的是,我觉得写起来很奇怪

free(p);
if (f) fclose(f);

我最终得到

if (p) free(p);
if (f) fclose(f);

我知道,这不是一个合理的原因,但这是我的情况:)

于 2009-12-16T11:41:24.080 回答
3

编译器,即使内联还不够聪明,无法知道函数会立即返回。将参数等推入堆栈并设置调用显然比测试指针更昂贵。我认为避免执行任何事情总是好的做法,即使任何事情都是无操作的。测试 null 是一种很好的做法。更好的做法是确保您的代码不会达到这种状态,从而完全消除对测试的需要。

于 2013-05-28T14:44:06.250 回答
2

指针变量可能为 NULL 的原因有两个:

  1. 因为该变量用于在类型理论中称为选项类型,并且保存指向对象的指针,或者 NULL 表示什么都没有

  2. 因为它指向一个数组,因此如果数组长度为零(malloc(0)允许返回 NULL,实现定义),则它可能为 NULL。

尽管这只是逻辑上的区别(在 C 中既没有选项类型也没有指向数组的特殊指针,我们只是对所有内容都使用指针),但始终应该清楚如何使用变量。

C 标准要求什么都不做是成功调用可能返回free(NULL)这一事实的必要对应物。这并不意味着一般的便利,这就是为什么例如确实需要非 NULL 参数的原因。通过传递不代表零长度数组的 NULL来滥用调用权限会让人感觉很糟糕和错误。malloc(0)NULLfclose() free(NULL)

于 2016-04-23T22:28:27.600 回答
0

如果您依赖 free(0) 就可以了,此时您的指针为空是正常的,请在评论中说明// may be NULL

这可能只是不言自明的代码,说是的,我知道,我也使用 p 作为标志

于 2009-12-16T11:46:42.827 回答
0

在移动环境中可以有一个自定义的 free() 实现。在这种情况下 free(0) 可能会导致问题。(是的,糟糕的实施)

于 2009-12-16T12:31:23.410 回答
0
if (p)
    free(p);

为什么要进行另一个明确的检查?

如果写这样的东西,它是为了传达指针可能为 NULL 的特定知识......以帮助可读性和代码理解。因为让它成为一个断言看起来有点奇怪:

assert(p || !p);
free(p);

(除了看起来很奇怪之外,如果您在许多此类情况下打开警告,编译器会抱怨“条件始终为真”。)

所以我认为这是一种很好的做法,如果从上下文中不清楚的话。

从前面的代码行中通常可以明显看出指针被期望为非空的相反情况:

...
Unhinge_Widgets(p->widgets);
free(p); // why `assert(p)`...you just dereferenced it!
...

但如果它不明显,那么拥有断言可能值得输入字符。

于 2018-02-19T08:54:55.820 回答