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

銀蟲 (小有名氣)
金蟲 (職業(yè)作家)

金蟲 (初入文壇)

銀蟲 (正式寫手)

| 6 | 1/1 | 返回列表 |
| 最具人氣熱帖推薦 [查看全部] | 作者 | 回/看 | 最后發(fā)表 | |
|---|---|---|---|---|
|
[考研] 291 求調(diào)劑 +3 | 化工2026屆畢業(yè)?/a> 2026-03-21 | 3/150 |
|
|---|---|---|---|---|
|
[考研] 318求調(diào)劑 +4 | plum李子 2026-03-21 | 7/350 |
|
|
[考研] 一志愿武理材料工程348求調(diào)劑 +3 |  ̄^ ̄゜汗 2026-03-19 | 5/250 |
|
|
[考研] 384求調(diào)劑 +3 | 子系博 2026-03-22 | 4/200 |
|
|
[考博] 招收博士1-2人 +3 | QGZDSYS 2026-03-18 | 4/200 |
|
|
[考研] 328求調(diào)劑,英語六級551,有科研經(jīng)歷 +5 | 生物工程調(diào)劑 2026-03-17 | 9/450 |
|
|
[考研]
|
Grand777 2026-03-21 | 3/150 |
|
|
[考研] 一志愿深大,0703化學(xué),總分302,求調(diào)劑 +4 | 七月-七七 2026-03-21 | 4/200 |
|
|
[考研] 311求調(diào)劑 +3 | 勇敢的小吳 2026-03-20 | 3/150 |
|
|
[考研] 302求調(diào)劑 +12 | 呼呼呼。。。。 2026-03-17 | 12/600 |
|
|
[基金申請]
學(xué)校已經(jīng)提交到NSFC,還能修改嗎?
40+4
|
babangida 2026-03-19 | 9/450 |
|
|
[考研] 346求調(diào)劑[0856] +4 | WayneLim327 2026-03-16 | 7/350 |
|
|
[考研] 265求調(diào)劑 +3 | Jack?k?y 2026-03-17 | 3/150 |
|
|
[考研] 083200學(xué)碩321分一志愿暨南大學(xué)求調(diào)劑 +3 | innocenceF 2026-03-17 | 3/150 |
|
|
[考研] A區(qū)線材料學(xué)調(diào)劑 +5 | 周周無極 2026-03-20 | 5/250 |
|
|
[考研] 一志愿華中農(nóng)業(yè)071010,總分320求調(diào)劑 +3 | 困困困困坤坤 2026-03-20 | 3/150 |
|
|
[考研] 085601材料工程專碩求調(diào)劑 +10 | 慕寒mio 2026-03-16 | 10/500 |
|
|
[考研] 材料工程專碩調(diào)劑 +5 | 204818@lcx 2026-03-17 | 6/300 |
|
|
[考研] 收復(fù)試調(diào)劑生 +4 | 雨后秋荷 2026-03-18 | 4/200 |
|
|
[論文投稿] 有沒有大佬發(fā)小論文能帶我個二作 +3 | 增銳漏人 2026-03-17 | 4/200 |
|