追了多年的開發框架,你還認識指標嗎?

2021-10-06 04:59:59 字數 4107 閱讀 8232

高階語言玩多了,可能很多人對指標或者彙編都淡忘了,本篇就和大家聊一聊指標,雖然c#中是不提倡使用的,但你能說指標在c#中不重要嗎?你要知道fcl內庫中大量的使用指標,如string,encoding,filestream等等數不勝數,如例**:

private unsafe static bool equalshelper(string stra, string strb)

while (num > 0 && *(int*)ptr2 == *(int*)ptr4) }}

}public unsafe mutex(bool initiallyowned, string name, out bool creatednew, mutexsecurity mutexsecurity)

private unsafe int readfilenative(safefilehandle handle, byte bytes, out int hr)

}

對,你覺得的美好世界,其實都是別人幫你負重前行,退一步說,指標的理解和不理解,對你研究底層原始碼影響是不能忽視的,指標相對比較抽象,考的是你的空間想象能力,可能現存的不少程式設計師還是不太明白,因為你缺乏所見即所得的工具,希望這一篇能幫你少走些彎路。

指標雖然比較抽象,但如果用windbg實時檢視記憶體布局,就很容易幫你理解指標的套路,下面先理解下指標的一些簡單概念。

&取址運算子,用於獲取某乙個變數的記憶體位址,*運算子,用於獲取指標變數中儲存位址指向的值,很抽象吧,看windbg。

unsafe

0:000> !clrstack -l

os thread id: 0x41ec (0)

child sp ip call site

locals:

0x0000005b1efff084 = 0x000000000000000a

0x0000005b1efff078 = 0x0000005b1efff084

0x0000005b1efff074 = 0x000000000000000a

仔細觀察locals中三組鍵值對。

<1>int* ptr = # => 0x0000005b1efff078 = 0x0000005b1efff084

int* ptr叫做指標變數,既然是變數必須得有自己的棧上位址0x0000005b1efff078,而這個位址上的值為0x0000005b1efff084,這不就是num的棧位址嘛,嘿嘿。

<2>var num2 = *ptr; => 0x0000005b1efff074 = 0x000000000000000a

*ptr就是用ptr的value[0x0000005b1efff084]獲取這個位址指向的值,所以就是10啦。

**也叫二級指標,指向一級指標變數位址的指標,有點意思,如下程式:ptr2指向的就是ptr的棧上位址, 一圖勝千言。

這種算術操作常常用在陣列或者字串等值型別集合,比如下面**:

fixed (int* ptr = new int[3] ) 

fixed (char* ptr2 = "abcd")

首先ptr預設指向陣列在堆上分配的首位址,也就是1的記憶體位址,當ptr++後會進入到下乙個整形元素2的記憶體位址,再++後又進入下乙個int的記憶體位址,也就是3,很簡單吧,我舉乙個例子:

一圖勝千言哈,console中的三個記憶體位址分別存的值是1,2,3哈, 不過這裡要注意的是,c#是託管語言,引用型別是分配在託管堆中,所以堆上位址會存在變動的可能性,這是因為gc會定期**記憶體,所以vs編譯器需要你用fixed把堆上記憶體位址固定住來逃過gc的打壓,在本例中就是0x000001bcaac82da0 - (0x000001bcaac82da8 +4)

古語說的好,一言不中,千言無用,你得拿一些例子活講活用,好吧,準備兩個例子。

我們都知道string中有乙個replace方法,用於將指定的字元替換成你想要的字元,可是c#中的string是不可變的,你就是對它吐口痰它都會生成乙個新字串,??的是用指標就不一樣了,你可以先找到替換字元的記憶體位址,然後將新字元直接賦到這個記憶體位址上,對不對,我來寫一段**,把abcgef替換成abcdef, 也就是將g替換為d

unsafe

");var len = s.length;

fixed (char* ptr = s)

cptr++;}}

console.writeline($"替換後:");

}----- output ------

替換前:abcgef

替換後:abcdef

執行結束啦!

看輸出結果沒毛病,接下來用windbg去執行緒棧上找找當前有幾個string物件的引用位址,可以在break處抓乙個dump檔案。

平時我們都是通過索引對陣列進行遍歷,如果和指標進行碰撞測試,您覺得誰快呢?如果我說索引方式就是指標的封裝,你應該知道答案了吧,下面來一起**到底快多少???

為了讓測試結果更加具有觀賞性,我準備遍歷1億個數字, 環境為:netframework4.8, release模式

static void main(string args)

console.writeline(" -------------- ");

for (int i = 0; i < 10; i++)

console.writeline("執行結束啦!");

console.readline();

}//遍歷陣列

有圖有真相哈,直接走指標比走陣列下標要快近一倍。

希望本篇能給在框架上奔跑的您乙個友情提醒,不要把指標忘啦,別人提倡不使用的指標在底層框架可都是大量使用的哦~

追了多年的開發框架,你還認識指標嗎?

高階語言玩多了,可能很多人對指標或者彙編都淡忘了,本篇就和大家聊一聊指標,雖然c 中是不提倡使用的,但你能說指標在c 中不重要嗎?你要知道fcl內庫中大量的使用指標,如string,encoding,filestream等等數不勝數,如例 private unsafe static bool equ...

你的燈還亮著嗎

1,搞清誰 問題的物件 有問題.2,問題的本質是什麼 大多數問題其實就是你期望的東西和你體驗的東西之間的差別.解決辦法是要麼改變期望,要麼改變體驗.3,不要把他們解決問題的方法誤認為是問題的定義 特別是在你使用自己的解決方法時 要搞清楚問題的定義 4,如果你太輕易的解決了他們的問題,他們永遠不會相信...

分手以後,TA的號碼你還留著嗎

分手?好吧,既然別後再也不聯絡,那手機號碼也不必留著。忍著痛,割捨了美麗的記憶,從此以後,期待天涯海角各自安好。引語 時隔多年,如果突然收到那個曾經恨之入骨的人的資訊或者 心情將如何?我想,時間的流逝早已沖淡了回憶中的痛苦和傷感了吧!取而代之的應該是驚喜和親切,畢竟人間沒有不散的宴席,也沒有不滅的仇...