我正在研究一个旧的代码库,几乎每次调用free()都会在其参数上使用强制转换.例如,
free((float *)velocity); free((float *)acceleration); free((char *)label);
其中每个指针都是相应的(和匹配的)类型.我完全没有理由这样做.这是非常古老的代码,所以我想知道它是否是K&R的东西.如果是这样,我实际上希望支持可能需要这个的旧编译器,所以我不想删除它们.
使用这些演员阵容有技术原因吗?我甚至没有看到使用它们的实用理由.在释放数据类型之前提醒自己有什么意义?
编辑:这个问题不是另一个问题的重复.另一个问题是这个问题的一个特例,如果亲密的选民能够阅读所有的答案,我认为这是显而易见的.
Colophon:我给出了"常量答案"的核对标记,因为这可能是为什么需要这样做的真正原因; 然而,关于它是一个ANSI C之前的习惯(至少在一些程序员中)的答案似乎是它在我的情况下使用的原因.很多人在这里有很多好处.感谢您的贡献.
如果指针是,则可能需要强制转换才能解析编译器警告const
.下面是一个代码示例,它会在不转换free参数的情况下发出警告:
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代码,你可能会发现这样的演员阵容.
类似的问题与参考.
当第一个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()
.
#define free(ptr) DIY_free(ptr, sizeof (*ptr))
A DIY_free()
是一种方法,特别是在调试模式下,对被释放的指针进行运行时分析.这通常与DIY_malloc()
添加声望,全局内存使用计数等相关联.我的小组在出现更多现代工具之前使用了这种技术多年.它必须将被释放的项目转换为最初分配的类型.
考虑到跟踪内存问题等花费了很多时间,像免费转换类型这样的小技巧将有助于搜索和缩小调试范围.
现代:Manos Nikolaidis @和@egur所述的避免const
和volatile
警告.我以为我会注意3场的效果预选赛:,,和.const
volatile
restrict
[编辑]增加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之前的事情,const
也void *
没有这样的事情.C89之前的函数原型. stdlib.h
本身就是委员会的一项发明.如果系统头文件free
根本无法声明,他们就会这样做:
extern free(); /* no `void` return type either! */
现在,关键点在于缺少函数原型意味着编译器没有进行参数类型检查.它应用了默认参数提升(仍然适用于可变参数函数调用的那些),就是这样.使每个呼叫站点的参数与被调用者的期望一致的责任完全在于程序员.
然而,这仍然并不意味着有必要free
在大多数K&R编译器上提出论据.功能就像
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指针