为什么将 free 的返回值转换为 void?

Ada*_*ton 84 c free casting legacy-code void

我正在阅读一本使用 C的书(Butenhof 的POSIX 线程编程,1997 年),我遇到了以下行:

(void)free(data);
Run Code Online (Sandbox Code Playgroud)

这里,data只是一个指向已分配结构的指针,

data = malloc(sizeof(my_struct_t));
Run Code Online (Sandbox Code Playgroud)

为什么是free被强制转换的结果void

根据我对 C 的理解,这似乎没有意义,原因有两个:

  • free 函数已经返回 void
  • 代码没有使用返回值(它甚至没有被分配给一个变量)

这本书写于 1997 年。这是某种遗产吗?

作者提到这些示例是在 Digital Unix 4.0d 上运行的,但如果您不打算使用该结果,我仍然无法想象有理由强制转换该函数的结果。

Eug*_*Sh. 102

如果我们谈论的是标准free函数,那么它的原型是

void free(void *ptr);
Run Code Online (Sandbox Code Playgroud)

因此演员表完全没用。
现在有些猜测。

作者可能忘记包含stdlib.h声明这个原型的头文件,所以编译器假设它的返回类型为int. 现在,在此代码的静态分析期间,编译器警告它认为是非void函数的未使用的返回值。这样的警告通常会通过将演员表添加到void.

  • 但请注意,如果由于推测的原因引入了强制转换,那么使用它来消除警告是*不正确的*。在这种情况下,编译器会将与实际不同的类型归因于“free”,从而导致调用具有未定义的行为(假设 C90 语义,其中调用未声明的函数并不在所有情况下本质上表现出 UB)。实际上,这可能会导致某些系统上出现“真正的”不当行为。正确的解决方案是为函数提供正确的声明。 (51认同)
  • 值得注意的是,“使用 POSIX 线程编程”中的示例多次未能包含相关的标准头。也许这是作者的一些不好的做法,他们可能使用了默认包含所有标准库的非标准编译器设置。 (11认同)

Jon*_*ler 76

这将是一个遗产的事情!

在有 C 标准之前,free()函数应该是(隐式的)类型int——因为还没有可靠的类型void可以返回。没有返回值。

当第一次修改代码以使用标准 C 编译器时,它可能没有包含<stdlib.h>(因为它在标准之前不存在)。旧代码会为分配函数(类似于和)编写extern char *malloc();(可能没有),并且不需要声明. 然后代码会将返回值转换为正确的类型——因为至少在某些系统上这是必要的(包括我学习 C 的系统)。externcalloc()realloc()free()

一段时间后,(void)添加了强制转换以告诉编译器(或者更有可能是lint)“free()故意忽略from 的返回值”以避免抱怨。但是最好添加<stdlib.h>并让其声明extern void free(void *vp);告诉lint或编译器没有可忽略的值。

JFTR:早在 80 年代中期,ICL Perq 最初是在面向字的体系结构上,并且char *内存位置的地址与指向同一位置的“anything_else 指针”非常不同。以char *malloc()某种方式宣布是至关重要的;将结果从它转换为任何其他指针类型至关重要。演员表实际上改变了 CPU 使用的数字。(当我们系统上的主内存从 1 MiB 升级到 2 MiB 时,也很高兴——因为内核使用了大约 3/4 MiB,这意味着用户程序可以在分页等之前使用 1 1/4 MiB。)

  • 我刚刚打开了 K&amp;R 第 1 版的副本,其中包含第 12 页上的 `free()` 的实现。177 隐式返回“int”。 (9认同)
  • 当然,在标准发布之前,“void”已添加到某些系统(也许是 Unix System III),但在编写 K&amp;R 1st Edn(1978 年)时,它还不是 C 的一部分。不返回值的函数在声明时没有返回类型(这意味着它返回“int”),只要不使用不返回的值,就没有问题。C90 标准必须将此类代码视为有效——否则,作为标准,它就会惨败。但 C99 删除了“隐式‘int’”和“隐式函数声明”规则。并不是世界上所有的代码都跟上了。 (9认同)
  • Op 声称这本书是在 1997 年写的。你在这里谈论的是非常早期的预标准“K&amp;R C”,似乎根本不可能有人会写一本关于它的书。据我所知,唯一存在的此类书确实是 K&amp;R 第一版。 (5认同)

JL2*_*210 12

不需要这个演员表。当时可能不会,因为 C 已经以 C89 的形式标准化了。

如果是这样,那将是由于隐式声明。这通常意味着编写代码的人忘记了#include <stdlib.h>并且正在使用静态分析器。这不是最好的解决方法,#include <stdlib.h>而是一个更好的主意。以下是 C89 中关于隐式声明的一些措辞:

如果函数调用中带括号的参数列表前面的表达式仅由一个标识符组成,并且没有对该标识符可见的声明,则该标识符被隐式声明,就像在包含函数调用的最里面的块中一样,声明

extern int identifier();
Run Code Online (Sandbox Code Playgroud)

出现了。

但这很奇怪,因为它们没有转换malloc任何一个的结果,并且mallocfree在同一个头文件中。

也有可能这只是一个错误或告诉读者free没有返回结果的某种方式。

  • 仅仅因为一种语言变得标准化并不意味着每个人都会立即更新他们的工具链和代码以符合它。老式的“K&amp;R”C 可能还会再坚持 8 年左右。不过,我同意静态分析工具需要对“free”进行强制转换而不是对“malloc”进行强制转换,这很奇怪。 (5认同)
  • @dan04你通常使用 malloc 的结果;)我不喜欢编写像 (void) printf (...) 这样的东西来阻止编译器发出警告,但是“必须在没有任何警告的情况下编译,即使是愚蠢的警告”是这样的发生在很多项目中。 (4认同)