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

下載本文檔

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

文檔簡介

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

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

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

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

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

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

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

8、了一個初始化結(jié)構(gòu)數(shù)組,顯示該數(shù)組,修改數(shù)組的一個元素,最后顯示更新的結(jié)果。代碼中針對挑選和更新要更改的元素提供了幾種備選辦法。其中一些是常用辦法,但事實上是擔(dān)心全的代碼模式:1: /* 用于演示指針運算問題的測試程序 */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: /* 正確,但沒有須

10、要采納的辦法 */39: ifdef correctbutwhy40: p = (struct twoints *)(char *)twointbuf + 2*sizeof(struct twoints);41: endif42:43: /* 以下是常見錯誤 */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: 我們研究一下如何拜訪要修改的其次個結(jié)構(gòu)元素。在第10 行中聲明的twointbuf 是一個結(jié)構(gòu)數(shù)組,相當(dāng)于指向該數(shù)組首地址的指針。我

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

溫馨提示

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

評論

0/150

提交評論