| 查看: 952 | 回复: 5 | |||
yalefield金虫 (文坛精英)
老汉一枚
|
[交流]
【转帖】指针是通往地狱的捷径 已有5人参与
|
|
作者:fera http://blog.chinaunix.net/space. ... log&cuid=376700 指针指向哪里?……毫无疑问,地狱。 半年前的某个星期,为了修改一个bug,我花了整整两天时间。 这是一个指针的错误,在传递参数的时候,应该传递一个指针而传递的是一个对象。因为程序流程一般执行不到这里,这个bug一直隐藏在水下。直到我有一天,不小心让程序执行了这段,结果程序崩溃了(当时我用root用户执行的,真幸运没有损坏系统)。有错误的这段代码是一位有8年编程经验的同事写的,指针的“邪恶”,可见一斑。 指针就好象一根绳子,绳子那边是什么被挡住了,我们看不见。你永远不知道那边是一头牛,还是一颗手榴弹。 指针是什么?你可以把它理解成拴着东西的绳子,也可以说是某个物体的柄(handle),随便什么,只要有助于你的理解。你的理解是对的,可惜只是一部分。 它实际上是一个无符号数,一个内存单元的编号;一般是unsigned long,在32bit CPU上,它是32位的,64位cpu上是64位的。在汇编语言里面,direct addressing、direct addressing采用的都是这个东西,只不过在C/C++中被封装成了指针。 现在我们知道了指针的本质,那么,可以通过成员来获得对象的首地址: #define ContainerOf(pointerToField, fieldName, ClassType) \ (ClassType *)((ulong)(pointerToField) - (ulong)((ClassType *)0->fieldName)) 也可以写出以下语句(为了隐藏某些信息,这样用户只知道返回的是一个句柄handle): typedef unsigned long ulong; typedef ulong SOME_HANDLE; SOME_HANDLE GetObjs() { A* p = new A[10](); return (SOME_HANDLE)p; } 嗯,看起来不错,指针的功能很强大。代码很优雅,……看似很好…… 问题是,对第二段代码,调用“h = GetObjs();”的用户执行了这样的操作:++h;他的本意是将指针移动到下一个元素,可他得到的是什么?假设GetObjs返回的是 0x00000001, ++h结果将是0x00000002,而不是期待中的0x00000001 + sizeof(A)。用户把它当成了下一个A类对象,进行了一些操作,于是,悲剧发生了……用户在内存中的数据全部错乱了,你的系统崩溃了。 是的,指针指向的只是一块内存,但是,这块内存合法吗?大小是多少?属于哪种类型?都是未知的。你会说,如果不知道这块内存属于哪个类型,指针算术就不会正确。你错了。指针的算术在编译时就知道了该怎么处理,运行时是没有类型信息的。就是将指针移动n * sizeof(A),而sizeof(A)编译时就确定了。 再考虑这段代码,把一组对象从一个数组拷贝到另一个: A ObjCopy(A * const dest, const A * const src, const int nItems) { assert(dest); assert(src); assert(nItems >= 0); while ( nItem-- ) *dest++ = *src++; return dest; } 忽略src里元素不足nItems个及dest没有nItems个空间的因素,这个函数依然是错误的。因为,如果dest - src < nItems的话,从第(dest - src)开始,src中的数据将被自己首部的数据给覆盖了。很不幸,你的数据又错了,系统可能又要崩溃了……至少,你会得到错误的结果。 好了,这仅仅是一级指针。换成二级指针呢? 正因为指针是程序的错误之源,java把对内存的操作封装起来,不对外提供指针,这样就避免了刚才的那些问题。C/C++的忠实粉丝不要误以为我在鼓吹java,我本人对于C/C++是特别钟爱的,因为它们的灵活性。相信大多数程序员喜欢它们也是因为这个。 写这篇文章的目的就是为了对指针的复杂性做一个说明,希望大家在使用指针的时候能够小心。 抛砖引玉,如果有更精辟的想法,希望您能赏光贴在后面! PS: 看了buxoman评论,觉得有必要澄清一点:对于一个指针,存在两个对象,一个是指针本身,一个是dereference的对象。因此在读我这篇文章时一定要搞清楚,什么时候说的是指针,什么时候说的是dereference的对象。 Copyleft (C) 2007-2009 raof01. 本文可以用于除商业外的所有用途。此处“用途”包括(但不限于)拷贝/翻译(部分或全部),不包括根据本文描述来产生代码及思想。若用于非商业,请保留此权利声明,并标明文章原始地址和作者信息;若要用于商业,请与作者联系(raof01@gmail.com),否则作者将使用法律来保证权利。 |
» 猜你喜欢
职称评审没过,求安慰
已经有51人回复
毕业后当辅导员了,天天各种学生超烦
已经有5人回复
26申博自荐
已经有3人回复
A期刊撤稿
已经有4人回复
垃圾破二本职称评审标准
已经有17人回复
投稿Elsevier的Neoplasia杂志,到最后选publishing options时页面空白,不能完成投稿
已经有22人回复
EST投稿状态问题
已经有7人回复
» 本主题相关价值贴推荐,对您同样有帮助:
NDJ-79型旋转粘度计上指针所显示的数据如何转变成实际粘度?
已经有6人回复
指针和指针变量
已经有9人回复
【分享】▁▂▃▄▅▆萤火虫指针+星辰随你而动、▆▅▄▃▂▁
已经有54人回复
管理理论每日谈更新
已经有65人回复
微尘、梦想
木虫 (知名作家)
- 程序强帖: 6
- 应助: 2 (幼儿园)
- 贵宾: 0.353
- 金币: 4757.9
- 散金: 3089
- 红花: 31
- 沙发: 247
- 帖子: 8788
- 在线: 1125小时
- 虫号: 1203290
- 注册: 2011-02-14
- 专业: 制造系统与自动化

2楼2011-03-23 16:31:00
claudebell
银虫 (小有名气)
- 应助: 0 (幼儿园)
- 金币: 353.8
- 红花: 2
- 帖子: 123
- 在线: 10.7小时
- 虫号: 1220145
- 注册: 2011-03-03
- 性别: GG
- 专业: 控制理论与方法
3楼2011-03-23 19:13:55

4楼2011-03-24 10:12:03
womeikongya
金虫 (初入文坛)
- 应助: 1 (幼儿园)
- 金币: 507.1
- 帖子: 22
- 在线: 3.1小时
- 虫号: 1107553
- 注册: 2010-09-25
- 性别: GG
- 专业: 电路与系统

5楼2011-03-27 18:08:19
luojin7653
银虫 (正式写手)
- 应助: 10 (幼儿园)
- 金币: 274.4
- 散金: 524
- 红花: 1
- 帖子: 752
- 在线: 232.9小时
- 虫号: 1208334
- 注册: 2011-02-21
- 性别: GG
- 专业: 环境分析化学

6楼2011-03-28 10:34:03













回复此楼