在C中,为什么有些人在释放指针之前投了指针呢?

我正在研究一个旧的代码库,几乎每个free()的调用都在其参数上使用一个强制转换。 例如,

free((float *)velocity); free((float *)acceleration); free((char *)label); 

每个指针都是对应的(和匹配的)types。 我根本看不到这一点。 这是非常古老的代码,所以我想知道这是否是一个K&R的事情。 如果是这样,我实际上希望支持那些可能需要这个的编译器,所以我不想删除它们。

有没有技术上的理由来使用这些演员? 我甚至没有看到使用它们的实用理由。 在释放数据之前,有什么要提醒自己的数据types?

编辑:这个问题不是其他问题的重复。 另外一个问题就是这个问题的一个特例,我认为如果接近的选民会阅读所有的答案,那么这个问题是显而易见的。

Colophon:我给“常量答案”一个复选标记,因为这是可能需要完成的一个真正的理由。 然而,关于它是一个ANSI C之前的习惯(至less在一些程序员之间)的答案似乎是它被用于我的情况的原因。 这里有很多人的好点子。 感谢你的贡献。

如果指针是const可能需要强制转换parsing编译器警告。 这里是一个代码的例子,它会导致一个警告而不会释放自由参数:

 const float* velocity = malloc(2*sizeof(float)); free(velocity); 

而编译器(gcc 4.8.3)说:

 main.c: In function 'main': main.c:9:5: warning: passing argument 1 of 'free' discards 'const' qualifier from pointer target type [enabled by default] free(velocity); ^ In file included from main.c:2:0: /usr/include/stdlib.h:482:13: note: expected 'void *' but argument is of type 'const float *' extern void free (void *__ptr) __THROW; 

如果你使用free((float*) velocity); 编译器停止抱怨。

预标准的C没有void*但只有char* ,所以你必须把所有传递的参数。 如果你遇到古代C代码,你可能会find这样的代码。

类似的问题与参考 。

当第一个C标准发布的时候,malloc和free的原型已经从char*变成了今天仍然有的void*了。

当然在标准C中,这样的演员是多余的,只是伤害可读性。

这里有一个自由的例子,如果没有强制转换就会失败:

 volatile int* p = (volatile int*)malloc(5 * sizeof(int)); free(p); // fail: warning C4090: 'function' : different 'volatile' qualifiers free((int*)p); // success :) free((void*)p); // success :) 

在C中你可以得到警告(在VS2012中有一个)。 在C ++中,你会得到一个错误。

除了罕见的情况,铸造只是膨胀的代码…

编辑:我铸造void*不是int*来演示失败。 它将像int*一样工作,将被隐式转换为void* 。 增加了int*代码。

旧的原因:1.通过使用free((sometype*) ptr) ,代码明确指出应该将指针视为free()调用的一部分。 当free()被一个(自己动手)的DIY_free()replace时,显式的DIY_free()是有用的。

 #define free(ptr) DIY_free(ptr, sizeof (*ptr)) 

DIY_free()是一种方法,特别是在debugging模式下,可以对正在释放的指针进行运行时分析。 这通常与一个DIY_malloc()来添加句子,全局内存使用计数等。我的团队使用这种技术多年之前,更现代的工具出现。 它有义务将被释放的项目转换为最初分配的types。

  1. 由于花费了很多时间来追踪内存问题等,所以类似于free'dtypes的小技巧将有助于search和缩小debugging。

现代化:避免像Manos Nikolaidis @和@egur那样的constvolatile警告。 以为我会注意到3个限定符的作用: constvolatilerestrict

添加char * restrict *rp2每@R ..评论

 void free_test(const char *cp, volatile char *vp, char * restrict rp, char * restrict *rp2) { free(cp); // warning free(vp); // warning free(rp); // OK free(rp2); // warning } int main(void) { free_test(0,0,0,0); return 0; } 

这是另一种替代假设。

我们被告知,这个程序是在C89之前编写的,这意味着它不能解决与free原型的某种不匹配问题,因为在C89之前不仅没有constvoid *类的东西,没有像C89之前的函数原型那样的东西。 stdlib.h本身就是委员会的发明。 如果系统头文件困扰于free声明,他们会这样做:

 extern free(); /* no `void` return type either! */ 

现在,关键是没有函数原型意味着编译器没有参数types检查 。 它应用了默认参数促销(与仍然适用于可变参数函数调用的相同),就是这样。 负责让每个现场的参数符合被调用者的期望完全由程序员来完成。

但是,这并不意味着有必要在大多数的K&R编译器上free提供这个参数。 像一个函数

 free_stuff(a, b, c) float *a; char *b; int *c; { free(a); free(b); free(c); } 

应该已经被正确编译了。 所以我认为我们在这里得到了一个程序来处理一个不寻常的环境的错误的编译器:例如,一个sizeof(float *) > sizeof(int)和编译器不会使用适当的调用指针的约定,除非你在调用点放置它们。

我不知道有这样的环境,但这并不意味着没有一个。 想到的最可能的候选者是在20世纪80年代早期的8位和16位微型编译器的“小C”编译器。 我也不会惊讶于早期的Crays有这样的问题。

free只接受非const指针作为参数。 所以在const指针的情况下,显式转换为非const指针是必需的。

无法释放C中的const指针

例如,对char *的强制转换不仅是不必要的,而且是错误的。

铸造float *char *是不正确的。

 free((float *)velocity); free((float *)acceleration); free((char *)label); 

按照C标准 , free()被声明为:

7.22.3.3 freefunction

概要

 1 #include <stdlib.h> void free(void *ptr); 

而且一个指针总是可以被转换为void *而不需要强制转换:

6.3.2.3指针

指向void的指针可以被转换为或指向任何对象types的指针。 指向任何对象types的指针都可以被转换为void和指向的指针; 结果应该等于原始指针。