| 5 | 1/1 | 返回列表 |
| 查看: 1031 | 回復: 5 | |||
| 當前只顯示滿足指定條件的回帖,點擊這里查看本話題的所有回帖 | |||
yalefield金蟲 (文壇精英)
老漢一枚
|
[交流]
【轉(zhuǎn)帖】指針是通往地獄的捷徑 已有5人參與
|
||
|
作者:fera http://blog.chinaunix.net/space. ... log&cuid=376700 指針指向哪里?……毫無疑問,地獄。 半年前的某個星期,為了修改一個bug,我花了整整兩天時間。 這是一個指針的錯誤,在傳遞參數(shù)的時候,應該傳遞一個指針而傳遞的是一個對象。因為程序流程一般執(zhí)行不到這里,這個bug一直隱藏在水下。直到我有一天,不小心讓程序執(zhí)行了這段,結果程序崩潰了(當時我用root用戶執(zhí)行的,真幸運沒有損壞系統(tǒng))。有錯誤的這段代碼是一位有8年編程經(jīng)驗的同事寫的,指針的“邪惡”,可見一斑。 指針就好象一根繩子,繩子那邊是什么被擋住了,我們看不見。你永遠不知道那邊是一頭牛,還是一顆手榴彈。 指針是什么?你可以把它理解成拴著東西的繩子,也可以說是某個物體的柄(handle),隨便什么,只要有助于你的理解。你的理解是對的,可惜只是一部分。 它實際上是一個無符號數(shù),一個內(nèi)存單元的編號;一般是unsigned long,在32bit CPU上,它是32位的,64位cpu上是64位的。在匯編語言里面,direct addressing、direct addressing采用的都是這個東西,只不過在C/C++中被封裝成了指針。 現(xiàn)在我們知道了指針的本質(zhì),那么,可以通過成員來獲得對象的首地址: #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; } 嗯,看起來不錯,指針的功能很強大。代碼很優(yōu)雅,……看似很好…… 問題是,對第二段代碼,調(diào)用“h = GetObjs();”的用戶執(zhí)行了這樣的操作:++h;他的本意是將指針移動到下一個元素,可他得到的是什么?假設GetObjs返回的是 0x00000001, ++h結果將是0x00000002,而不是期待中的0x00000001 + sizeof(A)。用戶把它當成了下一個A類對象,進行了一些操作,于是,悲劇發(fā)生了……用戶在內(nèi)存中的數(shù)據(jù)全部錯亂了,你的系統(tǒng)崩潰了。 是的,指針指向的只是一塊內(nèi)存,但是,這塊內(nèi)存合法嗎?大小是多少?屬于哪種類型?都是未知的。你會說,如果不知道這塊內(nèi)存屬于哪個類型,指針算術就不會正確。你錯了。指針的算術在編譯時就知道了該怎么處理,運行時是沒有類型信息的。就是將指針移動n * sizeof(A),而sizeof(A)編譯時就確定了。 再考慮這段代碼,把一組對象從一個數(shù)組拷貝到另一個: 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個空間的因素,這個函數(shù)依然是錯誤的。因為,如果dest - src < nItems的話,從第(dest - src)開始,src中的數(shù)據(jù)將被自己首部的數(shù)據(jù)給覆蓋了。很不幸,你的數(shù)據(jù)又錯了,系統(tǒng)可能又要崩潰了……至少,你會得到錯誤的結果。 好了,這僅僅是一級指針。換成二級指針呢? 正因為指針是程序的錯誤之源,java把對內(nèi)存的操作封裝起來,不對外提供指針,這樣就避免了剛才的那些問題。C/C++的忠實粉絲不要誤以為我在鼓吹java,我本人對于C/C++是特別鐘愛的,因為它們的靈活性。相信大多數(shù)程序員喜歡它們也是因為這個。 寫這篇文章的目的就是為了對指針的復雜性做一個說明,希望大家在使用指針的時候能夠小心。 拋磚引玉,如果有更精辟的想法,希望您能賞光貼在后面! PS: 看了buxoman評論,覺得有必要澄清一點:對于一個指針,存在兩個對象,一個是指針本身,一個是dereference的對象。因此在讀我這篇文章時一定要搞清楚,什么時候說的是指針,什么時候說的是dereference的對象。 Copyleft (C) 2007-2009 raof01. 本文可以用于除商業(yè)外的所有用途。此處“用途”包括(但不限于)拷貝/翻譯(部分或全部),不包括根據(jù)本文描述來產(chǎn)生代碼及思想。若用于非商業(yè),請保留此權利聲明,并標明文章原始地址和作者信息;若要用于商業(yè),請與作者聯(lián)系(raof01@gmail.com),否則作者將使用法律來保證權利。 |

木蟲 (知名作家)

銀蟲 (小有名氣)
金蟲 (初入文壇)

| 最具人氣熱帖推薦 [查看全部] | 作者 | 回/看 | 最后發(fā)表 | |
|---|---|---|---|---|
|
[考研] 287求調(diào)劑 +8 | 晨昏線與星海 2026-03-19 | 9/450 |
|
|---|---|---|---|---|
|
[考研] 一志愿北京化工大學 070300 學碩 336分 求調(diào)劑 +3 | vv迷 2026-03-22 | 3/150 |
|
|
[考研] 260求調(diào)劑 +3 | 朱芷琳 2026-03-20 | 4/200 |
|
|
[考研] 311求調(diào)劑 +3 | 26研0 2026-03-20 | 3/150 |
|
|
[考博] 招收博士1-2人 +3 | QGZDSYS 2026-03-18 | 4/200 |
|
|
[考研] 286求調(diào)劑 +10 | Faune 2026-03-21 | 10/500 |
|
|
[考研] 333求調(diào)劑 +5 | 87639 2026-03-21 | 7/350 |
|
|
[考研] 0805 316求調(diào)劑 +3 | 大雪深藏 2026-03-18 | 3/150 |
|
|
[考研] 0703化學297求調(diào)劑 +3 | Daisy☆ 2026-03-20 | 3/150 |
|
|
[考研] 296求調(diào)劑 +4 | www_q 2026-03-20 | 4/200 |
|
|
[考研] 277材料科學與工程080500求調(diào)劑 +6 | 自由煎餅果子 2026-03-16 | 6/300 |
|
|
[考研] 材料學學碩080502 337求調(diào)劑-一志愿華中科技大學 +4 | 順順順mr 2026-03-18 | 5/250 |
|
|
[考研] 一志愿山大07化學 332分 四六級已過 本科山東雙非 求調(diào)劑! +3 | 不想理你 2026-03-16 | 3/150 |
|
|
[考研] 求調(diào)劑 +3 | Ma_xt 2026-03-17 | 3/150 |
|
|
[考研] 一志愿中海洋材料工程專碩330分求調(diào)劑 +8 | 小材化本科 2026-03-18 | 8/400 |
|
|
[考研] 一志愿蘇州大學材料求調(diào)劑,總分315(英一) +5 | sbdksD 2026-03-19 | 5/250 |
|
|
[考研]
|
不想起名字112 2026-03-19 | 3/150 |
|
|
[考研] 302求調(diào)劑 +4 | 小賈同學123 2026-03-15 | 8/400 |
|
|
[考研] 一志愿,福州大學材料專碩339分求調(diào)劑 +3 | 木子momo青爭 2026-03-15 | 3/150 |
|
|
[考研] 333求調(diào)劑 +3 | 文思客 2026-03-16 | 7/350 |
|