指針是如何記住步長的?
01-05
首先問一下我的如下理解是否有誤——
1、指針是一個變數,有自己的數據和(可能沒數據)地址2、它指向另一個變數,是因為它保存的數據是那個變數的地址,而且是首地址,所以能夠通過指針找到那個變數3、定義或聲明一個變數,則開闢了一段內存
接著我仔細描述一下我的問題——我知道指針的步長是由其類型決定的,我想問的是在實際的底層操作中,指針的步長保存到哪裡去了(指針是怎麼記住這個步長的)?或者更大一點說,定義一個某類型的指針,底層到底做了什麼操作?如果僅僅只保存首地址,指針怎麼知道一跳一個步長?
也不是我謙虛,我一個運行時,怎麼能知道類型的尺寸呢?
編譯器已經決定了,就由這麼大的這個數目當做這個類型的指針的步長!
c和cpp的一個優點,也是其可以做系統級語言的原因之一,就是運行時不包含類型信息。
所以,在運行時,所有的指針原則上一律平等。
而對指針進行+1操作時,到底加幾的問題,是編譯時決定的。
size_t s = 1;void* pc = 0;pc = (void*)((int*)pc + s);比如這樣,等價於pc += sizeof(int) * s;
而pc = (void*)((double*)pc + s);就等價於pc += sizeof(double) * s;
//gcc限定……指針沒有記住步長,所有的指針移動距離都在編譯時都被額外乘以了類型的長度
編譯器乾的,編譯器知道類型,然後把+什麼的編譯成相應步長的增量。
沒有你想的那麼複雜,就是編譯的時候編譯器自動給你乘上了步長。比如有個int *p,p+2就被編譯器直接轉成了p+2*sizeof(int),也就是p+8。
在編譯層面完成的(也就是說彙編層寫死)。一個顯著的特徵是無論 x86 彙編還是 MIPS 彙編在訪問內存時都要手動指定基地址(立即數或者寄存器存儲值)偏移量。
編譯器根據類型確定步長
然後直接映射到彙編裡面
所以 void*按住標準是不能進行加減的
所以 你把一個int*轉換成char* 再加1 步進就只是1
編譯器決定的,然後生成了相應的彙編代碼。
指針不需要記住自己的步長,編譯器會將指針的類型映射到的彙編語言的數據類型,比如32位的機器,一個C語言里的int 型(4位元組),對應到彙編語言里的就是雙字(DD)define doubleword(一個word就是2個位元組)。所以指針移動一個步長,到彙編層,也能知道具體是移多少。彙編層會去處理這個步長。結構體步長 或是 數組步長 的移動也是類似的道理。
非常好的問題。當年我本科的時候用這個問題問過教授,教授猶豫了半天,說是記錄在首地址。但是這個回答和我的實驗結果不符。答案前面已經說的很好了,這是編譯時決定的。但是我們說的真的對么?還是建議你親自實驗一番。
推薦閱讀:
※C中有沒有將一個函數轉變為另一個函數的函數(例如求導運算)?
※函數實現的時候,將函數返回值另起一行書寫,這是一種好的代碼書寫風格么?
※C語言中volatile修飾符的作用?
※學習 C/C++ ,有什麼書籍推薦?
※C語言中定義int a[10][10],a是什麼類型?