C語(yǔ)言中可移植且可靠的指針運(yùn)算_第1頁(yè)
已閱讀5頁(yè),還剩2頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、c語(yǔ)言中可移植且可靠的指針運(yùn)算在中,指針變量是強(qiáng)大且有用的功能。指針變量使程序員不僅可以間接引用數(shù)據(jù)和函數(shù),還可以結(jié)合數(shù)組下標(biāo)來(lái)挑選、讀取和寫入數(shù)組項(xiàng)。但首先需要了解什么是指針和地址以及編譯器如何用法它們。不理解指針和地址會(huì)很快導(dǎo)致代碼故障。利用指針,我們可以編寫出許多語(yǔ)法正確的c語(yǔ)言代碼,來(lái)編譯和實(shí)現(xiàn)某種功能,但這種功能在不同的c編譯器實(shí)現(xiàn)中以及不同的目標(biāo)器件上可能有所不同。甚至可能與我們的期望不同。指針不是整數(shù)指針變量包含 c 語(yǔ)言數(shù)據(jù)的地址。例如,查看以下幾行代碼。int a, *p;/* 為指針給予某個(gè)目標(biāo)的地址 */p = &a;/* 解除引用指針以間接拜訪目標(biāo) */*p =

2、 0;上面的代碼將變量a 的值設(shè)置為0。應(yīng)用到a 的&運(yùn)算符返回一個(gè)表示該變量位置的值(地址)。假如將該值復(fù)制到一個(gè)指針變量,然后對(duì)指針解除引用(用法*運(yùn)算符),則該表達(dá)式表示原始變量a。這很簡(jiǎn)單讓人認(rèn)為該地址在數(shù)值上等于變量a 所在的計(jì)算機(jī)存儲(chǔ)器地址,但在c 語(yǔ)言中并沒(méi)有此類要求。以下示例可清晰地解釋最后一點(diǎn):考慮具有多個(gè)自立存儲(chǔ)區(qū)的 器件。對(duì)位于數(shù)據(jù)存儲(chǔ)器中器件地址100h 的變量用法地址運(yùn)算符時(shí)應(yīng)返回什么值?而對(duì)位于程序存儲(chǔ)器中器件地址100h 的另一個(gè)變量用法地址運(yùn)算符時(shí)又應(yīng)返回什么值?假如在兩種狀況下都回答 100h,那么在運(yùn)行時(shí)如何得知100h 是數(shù)據(jù)存儲(chǔ)器中的地址還是程序

3、存儲(chǔ)器中的地址呢?明顯,在這種狀況下,假如稍后要解除引用地址,則需要其他方式來(lái)確定應(yīng)拜訪哪個(gè)存儲(chǔ)器。“其他方式”可以是對(duì)地址運(yùn)算符返回的值舉行特別編碼(與mplab xc8 編譯器協(xié)作用法的技術(shù)),也可以用法傳達(dá)相同信息的特別指針類型限定符(mplab xc16 和xc32 編譯器用法該辦法)。為保持代碼的可移植性,不應(yīng)假設(shè)將整數(shù)賦給指針就會(huì)使指針能拜訪任何對(duì)象,即使該整數(shù)的值與某個(gè)對(duì)象的器件地址相同。因此對(duì)于上面的示例,為指針賦值立刻數(shù)100h(或者保留此值的整數(shù)變量)并不意味著該指針指向變量a。/* 我們發(fā)覺(jué)“a”被分配到地址100h*/int a, *p;/* 注:這涉及整數(shù)到指針的隱式

4、轉(zhuǎn)換 */p = 0x100;/* 沒(méi)人知道會(huì)發(fā)生什么!*/*p = 0;請(qǐng)記住,一種地址空間中的取指和存儲(chǔ)可能不像另一種地址空間中的取指和存儲(chǔ)一樣容易編譯器可能需要用法不同的寄存器和命令才干執(zhí)行拜訪?;谕瑯拥木売?,在定義指針時(shí),必需用法適當(dāng)?shù)闹羔橆愋拖薅ǚ?。因?yàn)?mplab xc8 對(duì)地址舉行編碼,因此它不用法特別地址空間限定符,而mplab xc16 和xc32 則用法。但是,兩種狀況下都必需適時(shí)用法通常的const 和volatile 限定符。限定符在數(shù)據(jù)定義中指定,假如想要牢靠地拜訪該數(shù)據(jù),則需要用法與引用該數(shù)據(jù)的指針相匹配的限定符。例如,用法mplabxc16 時(shí):_psv_ ch

5、ar buffer8 _attribute_(space(psv)在閃存程序存儲(chǔ)器中放置一個(gè)字符數(shù)組buffer,可通過(guò)“psv”(程序空間可視性)窗口舉行拜訪。挺直拜訪buffer 將使編譯器生成可確保psv 窗口(位于處理器地址空間中的特定位置)映射到閃存(包含“buffer”)中適當(dāng)位置的代碼。buffer 的“地址”是所需窗口設(shè)置與“buffer”在囫圇窗口中的可視區(qū)域內(nèi)的偏移量的組合。通過(guò)指針引用“buffer”中的項(xiàng)時(shí),必需用法如下指針:_psv_ char *bp;才干使編譯器生成正確的代碼。不帶_psv_限定符的“一般”指針不起作用。因此指針不僅僅是一個(gè)寬到可以保存“地址”的整

6、數(shù),它還具有關(guān)聯(lián)的目標(biāo)類型;c 語(yǔ)言數(shù)據(jù)地址不僅僅是一個(gè)計(jì)算機(jī)存儲(chǔ)器地址,它可由編譯器修改或優(yōu)化。c 編譯器還會(huì)考慮其他一些事項(xiàng)。出問(wèn)題的位置假如我們認(rèn)為指針只是一個(gè)值為(計(jì)算機(jī)存儲(chǔ)器)地址的整數(shù),并且認(rèn)為我們已了解地址的含義以及該存儲(chǔ)器中羅列數(shù)據(jù)的方式,我們可能會(huì)想要在所編寫的c 語(yǔ)言代碼中顯式執(zhí)行各式各樣的地址運(yùn)算,進(jìn)而在程序中嵌入底層運(yùn)行時(shí)環(huán)境的特定于實(shí)現(xiàn)的具體信息。這樣一來(lái),即使現(xiàn)在程序可以運(yùn)行,但假如針對(duì)其他處理器舉行編譯,可能就無(wú)法正常工作,或者可能在看起來(lái)無(wú)關(guān)緊要的更改后莫名停止工作。我們?cè)撊绾伪荛_這類問(wèn)題呢?1. 用法正確的指針類型。按照引用的數(shù)據(jù)挑選適用的指針類型。盡管在你添

7、加一系列轉(zhuǎn)換后程序會(huì)舉行編譯,但不要據(jù)此認(rèn)為程序會(huì)實(shí)際根據(jù)你的期望工作。它會(huì)根據(jù)你告知它的方式工作,這可能與你的期望有很大不同。2. 按照你將用來(lái)拜訪數(shù)據(jù)的結(jié)構(gòu)來(lái)分配數(shù)據(jù)3. 不要猜想數(shù)據(jù)類型的布局例如,可以分配一個(gè)字符緩沖區(qū),然后將該緩沖區(qū)的地址轉(zhuǎn)換為指向更大類型數(shù)據(jù)數(shù)組或結(jié)構(gòu)數(shù)組的指針。隨后你可能會(huì)通過(guò)不同類型的指針,有時(shí)拜訪字符型數(shù)據(jù),有時(shí)拜訪其他類型的數(shù)據(jù)。為此,必需知道更大類型的數(shù)據(jù)在字符數(shù)據(jù)上以及彼此之間的羅列方式。這十分危急而且簡(jiǎn)單出錯(cuò)。假如需要通過(guò)多類型“視圖”拜訪數(shù)據(jù),請(qǐng)將數(shù)據(jù)分配成聯(lián)合數(shù)組,然后通過(guò)聯(lián)合拜訪數(shù)據(jù)。編譯器將清晰你的意圖并協(xié)助你正的確現(xiàn)。示例下面的 c 程序建立

8、了一個(gè)初始化結(jié)構(gòu)數(shù)組,顯示該數(shù)組,修改數(shù)組的一個(gè)元素,最后顯示更新的結(jié)果。代碼中針對(duì)挑選和更新要更改的元素提供了幾種備選辦法。其中一些是常用辦法,但事實(shí)上是擔(dān)心全的代碼模式:1: /* 用于演示指針運(yùn)算問(wèn)題的測(cè)試程序 */2: include3: include4:5: struct twoints 6: uint8_t a;7: uint32_t b;8: ;9:10: static struct twoints twointbuf4 = 11: 1, 5, 2, 6, 3, 7, 4, 812: ;13:14: int main(int argc, char *argv)15: 16: s

9、truct twoints *p;17: size_t i;18:19: /* 輸出結(jié)構(gòu)數(shù)組 */20: printf(“before:nn”);21: i = 0;22: p = twointbuf;23: while (i a, (*p).b);25: +p;26: +i;27: 28: printf(“n”);29:30: /* 挑選下標(biāo)為2 的元素的正確辦法 */31: p = twointbuf + 2;32:33: /* 等效且同樣好的辦法 */34: ifdef alsoright35: p = &twointbuf2;36: endif37:38: /* 正確,但沒(méi)有須

10、要采納的辦法 */39: ifdef correctbutwhy40: p = (struct twoints *)(char *)twointbuf + 2*sizeof(struct twoints);41: endif42:43: /* 以下是常見錯(cuò)誤 */44: ifdef reallywrong45: p = (struct twoints *)(char *)twointbuf + 2*(sizeof(uint8_t) + sizeof(uint32_t);46: endif47: ifdef notsafe48: p = (struct twoints *)(size_t)two

11、intbuf + 2*sizeof(struct twoints);49: endif50:51: /* 修改元素2 */52: p->b = 0xffffffff;53:54: /* 顯示更新的數(shù)組 */55: printf(“after:nn”);56: i = 0;57: p = &twointbuf0;58: while (i a,(p i).b);60: +i;61: 62: printf(“n”);63:64: return 0;65: 我們研究一下如何拜訪要修改的其次個(gè)結(jié)構(gòu)元素。在第10 行中聲明的twointbuf 是一個(gè)結(jié)構(gòu)數(shù)組,相當(dāng)于指向該數(shù)組首地址的指針。我

12、們可以通過(guò)數(shù)組或指針語(yǔ)法來(lái)拜訪該數(shù)組中的元素,這兩種編碼風(fēng)格表示同一個(gè)意思。第31 行和第35 行中給出的備選辦法均是獵取指向數(shù)組中元素2 的指針的平安辦法。編譯器不會(huì)將“2”解讀成兩個(gè)字節(jié)或兩個(gè)“字”,而是解讀成元素0 和元素1 后面的元素的編號(hào)2。在第 40 行,我們看到了按照數(shù)組的字節(jié)地址以及前面元素的長(zhǎng)度(字節(jié))來(lái)計(jì)算結(jié)構(gòu)元素地址的示例。假如(char *)上的限定符與數(shù)組上的限定符(本示例中沒(méi)有)匹配,則這種辦法可行只要字符指針和數(shù)組均聲明為引用相同的地址空間,地址和增量映射到底層存儲(chǔ)的規(guī)章就會(huì)相同,且該代碼有效。但為什么要這樣做呢?用法c 語(yǔ)言提供的簡(jiǎn)潔明白的語(yǔ)法,編譯器將生成同樣正確或更有效的代碼。在第 45 行,此代碼假設(shè)結(jié)構(gòu)元素的長(zhǎng)度(字節(jié))是兩個(gè)成員的長(zhǎng)度之和。這是擔(dān)心全的假設(shè),由于編譯器可能必需對(duì)結(jié)構(gòu)舉行填充才干使兩個(gè)成員在自然字邊界上對(duì)齊。是否用法結(jié)構(gòu)填充將取決于目標(biāo)器件。第 48 行上的語(yǔ)句一開頭沒(méi)有將數(shù)組指針轉(zhuǎn)換為字符指針,而是轉(zhuǎn)換為大到足以保存指針的整數(shù),從而向編譯器躲藏了該值是特定地址空間中的地址的事實(shí)。隨后執(zhí)行與第40 行相同的地址運(yùn)算,并將結(jié)果轉(zhuǎn)換回指向結(jié)構(gòu)數(shù)組的指針。在這種狀況下,編譯器沒(méi)有機(jī)會(huì)對(duì)添加

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論