为什么将自由的返回值转换为无效?


82

我正在读一本使用C 的书(Butenhof的《使用POSIX线程编程》,1997年),并且遇到了以下问题:

(void)free(data);

data只是指向已分配结构的指针,

data = malloc(sizeof(my_struct_t));

为什么free被强制转换为void

从我对C的理解来看,这似乎没有任何意义,原因有两个:

  • 自由功能已经返回 void
  • 该代码未使用返回值(甚至未分配给变量)

这本书写于1997年。这是某种遗留的东西吗?

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


一些可能的解释可以在这里找到:stackoverflow.com/questions/689677/...
天宝

3
出于好奇,您的C书出版的日期是什么?(这是哪本书?)如果大约在1995年之前,可能会有一些理由–标准C编译器在那时之前并不普遍。如果在此之后出版并且仍然包含演员表(并且没有解释原因),请担心它在教您什么其他坏习惯。获取更新的书!
乔纳森·勒夫勒


3
正如我的原始帖子中所提到的,@ JonathanLeffler,该书于1997年出版,并使用UNIX 4.0d。这本书是David R. Butenhof撰写的“使用POSIX线程编程”。到目前为止,它非常有用,由POSIX线程标准的原始作者之一编写。
亚当·约翰斯顿

6
上周我一直在使用我的副本-是的,它仍然很有用。它写在“普遍存在的标准C”的风口浪尖上(我说“大约1995”)。“ UNIX 4.0d”听起来像Digital UNIX,这是Butenhof工作的地方,并且序言中也提到了它。free()在您无需模仿的情况下,将演员角色视为一种奇怪的事物。很久以前它是半相关的,但是不再相关了。
乔纳森·莱夫勒

Answers:


100

如果我们在谈论标准free功能,那么它的原型是

void free(void *ptr);

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

作者可能已经忘记了包含stdlib.h声明此原型的标头,因此编译器假定其返回类型为int。现在,在对该代码进行静态分析时,编译器警告其未使用的返回值被认为是非void函数。通常通过将强制转换添加到来消除此类警告void


50
但是请注意,如果由于推测的原因引入了强制类型转换,那么使用它来使警告静音是不正确的。在这种情况下,编译器将为其分配一个与free实际不同的类型,结果是该调用具有未定义的行为(假设C90语义,其中调用未声明的函数并不固有地在所有情况下都显示UB)。实际上,在某些系统上会导致真正的错误行为是合理的。正确的解决方案是为函数提供正确的声明。
John Bollinger

11
值得注意的是,“使用POSIX线程编程”中的示例屡屡未能包含相关的标准标头。也许这是作者的一种不好的做法,他们本可以使用默认情况下包括所有标准库的非标准编译器设置。
伦丁

74

这将是一件遗留的事情!

在有了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。)


9
我刚刚打开了K&R第一版的副本,其中包含free()p 的实现。177隐式返回int
前nihilo

9
当然- void在标准发布之前已将其添加到某些系统(可能是Unix System III)中,但是在编写K&R 1st Edn(1978年)时,这并不是C的一部分。没有返回值的函数声明为没有返回类型(这意味着它返回了int),只要您不使用未返回的值,就没有问题。C90标准必须将这种代码视为有效,否则将像标准一样惨遭失败。但是C99删除了“隐式int”和“隐式函数声明”规则。并非世界上所有代码都赶上了。
乔纳森·莱夫勒

5
Op声称这本书是1997年写的。您在这里谈论的是非常早的标准版“ K&R C”,似乎根本没有人会写一本书。据我所知,唯一存在的此类书籍的确是K&R第一版。
伦丁

如果您认为可以避免使用隐式声明,那么通常不包含标头(如果是quixotic的做法),因为人们认为这样做会减少构建时间。
斯宾塞

有人使用(void)演员表printf()吗?
路易斯·科罗拉多

11

不需要此演员表。当时可能还没有,因为C已经以C89的形式标准化了。

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

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

extern int identifier();

出现了。

但是,这是奇怪,因为他们不投的结果malloc要么,并mallocfree在相同的头文件。

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


5
仅仅因为一种语言被标准化并不意味着每个人都会立即更新他们的工具链和代码以符合它。老式的“ K&R” C可能还会再停留8年,这似乎是合理的。不过,我同意这是奇怪的是一个静态分析工具将需要强制的free,但不适合malloc
dan04

4
@ dan04您通常使用malloc的结果;)我不喜欢编写(void)printf(...)之类的东西来停止编译器随地吐痰的警告,但是“必须在没有任何警告的情况下进行编译,即使是愚蠢的警告也是如此”在很多项目中都会发生。
richardb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.