51指標定義

2021-05-26 07:35:39 字數 3289 閱讀 2737

c51指標型別和儲存區的關係詳解(轉貼)

一、儲存型別與儲存區關係

data     --->    可定址片內ram

bdata    --->    可位定址的片內ram

idata    --->    可定址片內ram,允許訪問全部內部ram

pdata    --->    分頁定址片外ram (movx @r0) (256 byte/頁)

xdata    --->    可定址片外ram (64k 位址範圍)

code     --->    程式儲存區 (64k 位址範圍),對應movc @dptr

二、指標型別和儲存區的關係

對變數進行宣告時可以指定變數的儲存型別如:

uchar data x和data uchar x相等價都是在內ram區分配乙個位元組的變數。

同樣對於指標變數的宣告,因涉及到指標變數本身的儲存位置和指標所指向的儲存區位置不同而進行相應的儲存區型別關鍵字的使用如:

uchar xdata * data pstr

是指在內ram區分配乙個指標變數("*"號後的data關鍵字的作用),而且這個指標本身指向xdata區("*"前xdata關鍵字的作用),可能初學c51時有點不好懂也不好記。沒關係,我們馬上就可以看到對應「*」前後不同的關鍵字的使用在編譯時出現什麼情況。

......

uchar xdata tmp[10];    //在外ram區開闢10個位元組的記憶體空間,位址是外ram的0x0000-0x0009

......

第1種情況:

uchar data * data pstr;

pstr="tmp";

首先要提醒大家這樣的**是有bug的, 他不能通過這種方式正確的訪問到tmp空間。 為什麼?我們把編譯後看到下面的彙編**:

mov 0x08,#tmp(0x00)        ;0x08是指標pstr的儲存位址

看到了嗎!本來訪問外ram需要2 byte來定址64k空間,但因為使用data關鍵字(在"*"號前的那個),所以按keilc編譯環境來說就把他編譯成指向內ram的指標變數了,這也是初學c51的朋友們不理解各個儲存型別的關鍵字定義而造成的bug。特別是當工程中的預設的儲存區類為large時,又把tmp[10] 宣告為uchar tmp[10] 時,這樣的bug是很隱秘的不容易被發現。

第2種情況:

uchar xdata * data pstr;

pstr = tmp;

這種情況是沒問題的,這樣的使用方法是指在內ram分配乙個指標變數("*"號後的data關鍵字的作用),而且這個指標本身指向xdata區("*"前xdata關鍵字的作用)。編譯後的彙編**如下。

mov 0x08,#tmp(0x00)        ;0x08和0x09是在內ram區分配的pstr指標變數位址空間

mov 0x09,#tmp(0x00)

這種情況應該是在這裡所有介紹各種情況中效率最高的訪問外ram的方法了,請大家記住他。

第3種情況:

uchar xdata * xdata pstr;

pstr="tmp";

這中情況也是對的,但效率不如第2種情況。編譯後的彙編**如下。

mov dptr, #0x000a;0x000a,0x000b是在外ram區分配的pstr指標變數位址空間

mov a, #tmp(0x00)

mov @dptr, a

inc dptr

mov a, #tmp(0x00)

movx @dptr, a

這種方式一般用在內ram資源相對緊張而且對效率要求不高的專案中。

第4種情況:

uchar data * xdata pstr;

pstr="tmp";

如果詳細看了第1種情況的讀者發現這種寫法和第1種很相似,是的,同第1 種情況一樣這樣也是有bug的,但是這次是把pstr分配到了外ram區了。編譯後的彙編**如下。

mov dptr, #0x000a ;0x000a是在外ram區分配的pstr指標變數的位址空間

mov a, #tmp(0x00)

movx @dptr, a

第5種情況:

uchar * data pstr;

pstr="tmp";

大家注意到"*"前的關鍵字宣告沒有了,是的這樣會發生什麼事呢?下面這麼寫呢!對了用齊豫的一首老歌名來說就是 「請跟我來」,請跟我來看看編譯後的彙編**,有人問這不是在講c51嗎? 為什麼還要給我們看彙編**。c51要想用好就要盡可能提公升c51編譯後的效率,看看編譯後的彙編會幫助大家盡快成為生產高效c51**的高手的。還是看**吧!

mov 0x08, #0x01;0x08-0x0a是在內ram區分配的pstr指標變數的位址空間

mov 0x09, #tmp(0x00)

mov 0x0a, #tmp(0x00)

注意:這是新介紹給大家的,大家會疑問為什麼在前面的幾種情況的pstr指標變數都用2 byte空間而到這裡就用3 byte空間了呢?這是keilc的乙個系統內部處理,在keilc中乙個指標變數最多占用 3 byte空間,對於沒有宣告指標指向儲存空間型別的指標,系統編譯**時都強制載入乙個位元組的指標型別分辯值。具體的對應關係可以參考keilc的help中c51 user's guide。

第6種情況:

uchar * pstr;

pstr="tmp";

這是最直接最簡單的指標變數宣告,但他的效率也最低。還是那句話,大家一起說好嗎!編譯後的彙編**如下。

mov dptr, #0x000a        ;0x000a-0x000c是在外ram區分配的pstr指標變數位址空間

mov a, #0x01

mov @dptr, a

inc dptr

mov dptr, #0x000a

mov a, #tmp(0x00)

mov @dptr, a

inc dptr

mov a, #tmp(0x00)

movx @dptr, a

這種情況很類似第5種和第3種情況的組合,既把pstr分配在外ram空間了又增加了指標型別的分辨值。

小結一下:大家看到了以上的6種情況,其中效率最高的是第2種情況,既可以正確訪問ram區又節約了**,效率最差的是第 6種,但不是說大家只使用第2種方式就可以了,還要因情況而定,一般說來應用51系列的系統架構的內部ram資源都很緊張,最好大家在定義函式內部或程式段內部的區域性變數使用內ram,而盡量不要把全域性變數宣告為內ram區中。所以對於全域性指標變數我建議使用第3 種情況,而對於區域性的指標變數使用第2種方式。

c51是很靈活的,也很好理解和使用,但要成為笑傲江湖的一代高手還是要多想多練,沒有實際專案的鍛鍊是不容易提高的。希望這篇文章對大家一點用處 。

5 1 指標與位址 C

一元運算子 是間接定址或間接引用運算子。當它作用與指標時,將訪問指標所指向的物件。我們在這裡假定 x 與 y 是整數,而 ip 是指向 int 型別的指標,下面的 說明了如何在程式中宣告指標以及如何使用運算子 和 intx 1 y 2 z 10 int ip ip is a pointer to i...

指標詳解系列1 指標的定義

指標的描述 以下的所有地方都基於c89標準 指標與陣列,結構,聯合等一樣也是一種資料物件,其值是另外乙個物件的位址 這是重點,指標變數裡面儲存的內容是另外乙個物件的位址 指標 得名於這樣的事實 其內容 指向 另外乙個物件。指標可以指向任何型別 完整型別的或者不完整型別 的物件。乙個指標還可以指向其他...

指標(三) 指標陣列

指標陣列定義 一維指標陣列的定義形式 型別名 陣列名 陣列長度 char p 5 乙個陣列,若其元素均為指標型別資料,稱為指標陣列,指標陣列中的每乙個元素都相當於乙個指標變數。指標陣列的初始化 使用位址為指標陣列初始化 char p 5 指標陣列和二級指標 int main char temp 定義...