- 论坛徽章:
- 2
|
free空指针
本帖最后由 OwnWaterloo 于 2012-04-24 17:53 编辑
free空指针,即表达式 free(0) 在:
- C89 7.21.3.3
- C99 7.10.3.2
- C11 7.20.3.2
中都有对此行为的描述:
The free function
...
If ptr is a null pointer, no action occurs.
... 它是完全合法的。
因此,十分常见的语句if (p) free(p);其实是不必要的,可以化简为表达式并直接free(p)。
选择free(p)并不需要太多的理由。如果简洁不够,那 “省下if (p)测试在效率上的开销” 应该可以引发C程序员的“口水反应”了。
相反,放弃if (p) free(p);似乎需要驳斥更多的理由:
- 预防free的实现不符合规范?
著名的鲁棒性原则(robustness principle)是错的,看看它是如何把当今的Web搅得一团糟! [1]_
.. [1] Martian Headsets(火星人的耳机)
除非检测 garbage 是责任的一部分 —— 如free函数那样 —— 否则 garbage in 就应该 garbage out 。
- 这会不会太理想主义了?在等待出错方修正时,是不是也可以做点什么?解决问题应该优先于划分责任?
当然可以做点什么,那就是将这样的free实现丢进火坑,换另一种符合标准的free实现。
ECMAScript代码通常直接面对坐在浏览器前的最终用户,而C代码更多的是面向程序员。
因此,通常来说C程序员对C编译器的选择权相比Web程序员对Web浏览器选择权要高得多。
- 假如没有选择权呢?是否应该将代码改为if (p) free(p);?
即使在这种不幸的情况下,依然不需要将代码改为if (p) free(p);。
不改动源代码的情况下让free(p)增加检测并不是太难的事情,比如:
- 实现checked_free
- /* checked_free.c */
- #include <stdlib.h>
- void checked_free(void* p) { if (p) free(p); }
复制代码 - 替换free
对除了 checked_free.c 之外的所有文件增加宏定义#define free checked_free,并重新编译。
- 链接
当free的错误被修复,或者移植到另一个一开始就没有错误的平台时,就可以彻底与 checked_free.c 说拜拜。
------ ------ 以上正文 ------ ------
另外有一些问题。
- 真的有free(0)不是什么都不做的实现么……
- 排版
本来我是用rst的,但我猜你不用这个……所以就直接往论坛上帖了……
论坛没有inline code,我就用Times New Roman字体了。居然没有Courier New……
inline link也不适合纸质文档, 但论坛也没有脚注什么的……
排版就交给你了……
- Web程序员
那个行业我不熟, 所以不知道准确的职称应该叫什么。
想指的是那些写 HTML/CSS/JS 并且被浏览器兼容性搞得焦头烂额的程序员。
应该叫Web前端程序员么?
- 最初给你提到的处方
- define free(p) ( (void)((p)? (free)((p)): (void)0) )
复制代码 想了想, 问题不少……
- p 被求值多次
比如free(malloc(12))。
虽然if (malloc(12)) free(malloc(12))也是不可以的……
- (free)的用法太过刁钻……
- free不是函数
例如库提供的是void __builtin__free(void* p);,并有一个宏#define free __builtin__free。
- free 不是函数,且 __builtin__free 不是单参数
例如:- void __builtin__free(void* p, char const* file, int line);
复制代码 对这种实现,正文中提到的处方虽不致错,但会丢失信息。
可以这样改:
- void checked_free(void* p, char const* file, int line) {
- if (p) __builtin__free(p, file, line);
- }
- #define free(p) checked_free((p), __FILE__, __LINE__)
复制代码 只是我不确定为了这样一种极少发生的事占篇幅去详细讨论有无必要……
PS: 论坛上排个版还真不科学…… 预览功能也不够好,会破坏格式…… |
|