指針是如何記住步長的?

首先問一下我的如下理解是否有誤——

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是什麼類型?

TAG:C編程語言 | CC | 指針 | C指針 |