青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 74, 文章 - 0, 評論 - 26, 引用 - 0
數(shù)據(jù)加載中……

新時代的門前 32位世界中的64位編程

為16、32、64位架構編寫可移植代碼

  與16位相比,32位意味著程序更快、可直接尋址訪問更多的內(nèi)存和更好的處理器架構。鑒于此,越來越多的程序員已經(jīng)開始考慮利用64位處理器所帶來的巨大優(yōu)勢了。

  克雷研究(Cray Research 應為品牌名)計算機已經(jīng)開始使用64位字,并可訪問更大的內(nèi)存地址。然而,作為正在向開發(fā)標準軟件和與其他操作系統(tǒng)相互努力的一部分,我們已經(jīng)停止了移植那些原本基于32位處理器的代碼。事實上,我們不斷遇到我們稱之為“32位主義”的代碼,這些代碼都是在假定機器字長為32位的情況下編寫的,因而很難移植這種代碼,所以必須確立一些簡單的指導方針,以便助于編寫跨16、32、64位處理器平臺的代碼。

  由于有一些遺留問題,C語言在數(shù)據(jù)類型和數(shù)據(jù)構造方面,顯得有點過剩了。可以使用的不僅僅是char、short、int和long類型,還有相應的unsigned(無符號)類型,當然你可在結構(structure)和聯(lián)合(union)中混合使用,可以在聯(lián)合中包含結構,再在結構中包含聯(lián)合,如果還嫌數(shù)據(jù)類型不夠復雜,還可以轉(zhuǎn)換成比特位,當然也可以把一種數(shù)據(jù)類型轉(zhuǎn)換成另一種你想要的數(shù)據(jù)類型。正是因為這些工具太強大,如果不安全地使用它們,就有可能會傷到自己了。

  高級代碼的高級結構

  在Kernighan和Plauger經(jīng)典的《The Elements of Programming Style》一書中,他們的建議是“選擇使程序看上去簡單的數(shù)據(jù)表示法”。對個人而言,這意味著為高級編程使用高級數(shù)據(jù)結構,而低級編程使用低級數(shù)據(jù)結構。

  在我們移植的程序中,有一個常見的32位主義bug,不如拿它來做個例子,科內(nèi)爾大學編寫的用于網(wǎng)間互訪的路由協(xié)議引擎,在伯克利網(wǎng)絡環(huán)境下(指TCP/IP),自然是使用inet_addr( )來把表示Internet地址的字符串轉(zhuǎn)換成二進制形式。Internet地址碰巧也是32位的,就如運行伯克利網(wǎng)絡系統(tǒng)的其他計算機一樣,都是有著同樣的字寬。

  但也存在著有關Internet地址的高級定義:in_ addr結構。這個結構定義包括了子域s_ addr,它是一個包含了Internet地址的unsigned long標量。inet_addr()接受一個指向字符的指針,并且返回一個unsigned long,在轉(zhuǎn)換地址字符串過程中如果發(fā)生錯誤,inet_addr將返回-1。

  程序Gated讀取以文本格式存放Internet地址的配置文件,并把它們放入sockaddr_in(這是一個包含了結構in_addr的高級結構)。例1(a)中的代碼可以在32位電腦上正常運行,但移植到克雷研究計算機上,卻無法運行,為什么呢?

  例1:高級代碼的高級結構

  (a)

struct sockaddr_in saddrin
char *str;

if ((saddrin.sin_addr.s_addr = inet_addr(str)) == (unsigned long)-1) {
 do_some_error_handling;
}

  (b)

struct sockaddr_in saddrin
char *str;

if (inet_aton(str, &saddrin.sin_addr) ! = OK) {
 do_some_error_handling;
}

  因為只要inet_addr能夠正確地解析字符串,那么一切OK。當inet_addr在64位計算機上返回一個錯誤時,這段代碼卻未能捕捉到。你必須要考慮比較語句中的數(shù)據(jù)位寬,來確定到底是哪出了錯。

  首先,inet_addr返回錯誤值——unsigned long -1,在64位中表示為比特位全為1,這個值被存儲在結構in_addr下的子域s_addr中,而in_addr必須是32位來匹配Internet地址,所以它是一個32比特位的unsigned int(在我們的編譯器上,int是64位)。現(xiàn)在我們存儲進32個1,存儲進的值將與unsigned long -1比較。當我們存儲32個1于unsigned int時,編譯器自動把32位提升為64位;這樣,數(shù)值0x00000000 ffffffff與0xffffffff ffffffff的比較當然就失敗了。這是一個很難發(fā)現(xiàn)的bug,特別是在這種因為32位到64位的隱式提升上。

  那我們對這個bug怎么辦呢?一個解決方法是在語句中比較0xffffffff,而不是-1,但這又會使代碼更加依賴于特定大小的對象。另一個方法是,使用一個中間的unsigned long變量,從而在把結果存入sockaddr_in前,執(zhí)行比較,但這會讓程序代碼更復雜。

  真正的問題所在是,我們期望一個unsigned long值與一個32位量(如Internet地址)相等。Internet地址必須以32位形式進行存儲,但有些時候用一個標量,來訪問這個地址的一部分,是非常方便的。在32位字長的電腦中,用一個long數(shù)值(常被當作32位)來訪問這個地址,看上去沒什么問題。讓我們暫時不想一個低級的數(shù)據(jù)項(32位Internet地址)是否與一個機器字相等,那么高級數(shù)據(jù)類型結構in_addr就應該被一直使用。因為in_addr中沒有無效值,那么應有一個單獨的狀態(tài)用作返回值。

  解決方案是定義一個新的函數(shù),就像inet_addr那樣,但返回一個狀態(tài)值,而且接受一個結構in_addr作為參數(shù),參見例1(b)。因為高級的數(shù)據(jù)元素可以一直使用,而返回的值是沒有溢出的,所以這個代碼是可以跨架構移植的,而不管字長是多少。雖然伯克利發(fā)布了NET2,其中的確定義了一個新的函數(shù)inet_aton(),但如果試著改變inet_addr()中的代碼,將會損壞許多程序。

  低級代碼的低級結構

  低級編程意味著直接操縱物理設備或者特定協(xié)議的通訊格式,例如,設備驅(qū)動程序經(jīng)常使用非常精確的位模式來操縱控制寄存器。此外,網(wǎng)絡協(xié)議通過特定的比特位模式傳輸數(shù)據(jù)項時,也必須適當?shù)剞D(zhuǎn)譯。

  為了操縱物理數(shù)據(jù)項,此處的數(shù)據(jù)結構必須準確地反映被操縱的內(nèi)容。比特位是一個不錯的選擇,因為它們正好指定了比特的位數(shù)及排列。事實上,正是這種精確度,使比特位相對于short、int、long,更好地映像了物理結構(short、int、long會因為電腦的不同而改變,而比特位不會)。

  當映像一個物理結構時,是通過定義格式來使比特位達到這種精度的,這就使你必須一直使用一種編碼風格來訪問結構。此時的每個位域都是命名的,你寫出的代碼可直接訪問這些位域。當訪問物理結構時,有件事可能你并不想去做,那就是使用標量數(shù)組(short、int、or long),訪問這些數(shù)組的代碼都假定存在一個特定的比特位寬,當移植這些代碼到一臺使用不同字寬的電腦上時,就可能不正確了。

  在我們移植PEX圖像庫時遇到的一個問題,就涉及到其映像的協(xié)議消息結構。在某臺電腦上,如果int整型的長度與消息中的元素一樣,那例2(a)中的代碼就會工作得很正常。32位的數(shù)據(jù)元素在32字長的電腦上沒有問題,拿到64位的克雷計算機上,它就出錯了。對例2(b)而言,不單要改變結構定義,還要改變所有涉及到coord數(shù)組的代碼。這樣,擺在我們面前就有兩個選擇,要么重寫涉及此消息的所有代碼,要么定義一個低級的結構和一個高級的結構,然后用一段特殊的代碼把數(shù)據(jù)從一個拷貝到另一個當中,不過我也不期望可以找出每個對zcoord = draw_ msg.coord[2]的引用,而且,當現(xiàn)在需要移植到一個新架構上時,把所有的代碼都改寫成如例2(c)所示無疑是一項艱苦的工作。這個特殊的問題是由于忽視字長的不同而帶來的,所以不能假設在可移植的代碼中機器字長、short、int、long都是具有同樣的大小。

  例2:低級代碼的低級結構

  (a)

struct draw_msg {
 int objectid;
 int coord[3];
}

  (b)

struct draw_msg {
 int objectid:32;
 int coord1:32;
 int coord2:32;
 int coord3:32;
}

  (c)

int *iptr, *optr, *limit;
int xyz[3];

iptr = draw_msg.coord;
limit = draw_msg.coord + sizeof(draw_msg.coord);

optr = xyz;
while (iptr < limit)
*optr++ = *iptr++;
結構打包和字對齊

   正是因為編譯器會對結構進行打包,所以不同計算機上字長的變化,還導致了另一個問題。C編譯器在字(word)的邊界上對齊字長,當具有一個字長的數(shù)據(jù)后面緊接著一個較小的數(shù)據(jù)時,這種方法會產(chǎn)生內(nèi)存空缺(不過也有例外,比如說當有足夠多的小數(shù)據(jù)剛好可以填充一個字時)。

   一些聰明的程序員在聲明聯(lián)合時,往往在其中會帶有兩個或更多的結構,其中一個結構剛好填充聯(lián)合,另一個則可以用來從不同的角度來看待這個聯(lián)合,參見例3(a)。假設這段代碼是為16位字長的計算機所寫,int為16位,long為32位,那么存取這個結構的代碼將會得到正常的映射關系(如圖1),而例3(b)中的代碼也會按預期的那樣工作。可是,如果這段代碼一旦移植到另一臺具有32位字長的計算機上時,映射關系就改變了。如果新計算機上的編譯器允許你使用16位的int,那么字的對齊就會像圖2所示了,或者如果編譯器遵循K&R約定,那么int將會和一個字(32比特)一樣長,對齊就如圖3所示,在任一情況下,這都將導致問題。




  例3:結構打包和字對齊

  (a)

union parse_hdr {
 struct hdr {
  char data1;
  char data2;
  int data3;
  int data4;
} hdr;
struct tkn {
 int class;
 long tag;
} tkn;
} parse_item;

  (b)

char *ptr = msgbuf;

parse_item.hdr.data1 = *ptr++;
parse_item.hdr.data2 = *ptr++;
parse_item.hdr.data3 = (*ptr++ << 8 | *ptr++);
parse_item.hdr.data4 = (*ptr++ << 8 | *ptr++);

if (parse.tkn.class >= MIN_TOKEN_CLASS && parse.tkn.class <= MAX_TOKEN_CLASS) {
 interpret_tag(parse.tkn.tag);
}

  在第一個情況中(圖2),tag域不是像期望的那樣線性拉長,而被填充了一些垃圾。而在第二個情況中(圖3),無論是class還是tag域,都不再有意義,兩個char值因為被打包成一個int,所以也都不再正確。再次強調(diào),首先不要假設標準數(shù)據(jù)類型大小一樣,其次還要了解它們是怎樣被映射成其他數(shù)據(jù)類型的,這才是書寫可移植代碼的最好方法。

  機器尋址特性

  幾乎所有的處理器都在字邊界上以字為單位進行尋址,而且通常都為此作了一些優(yōu)化。另有一些的處理器允許其他類型的尋址,如以字節(jié)為單位尋址、或在半個字邊界上以半字為單位尋址,甚至還有一些處理器有輔助硬件允許在奇數(shù)邊界上同時以字和半字進行尋址。

  尋址機制在不同計算機上會有所變化,最快的尋址模式是在字邊界上以字為單位進行尋址。其他方式的尋址需要輔助硬件,通常都會對內(nèi)存訪問增加了一些時鐘周期。而這些過多的模式和特殊硬件的支持,是與RISC處理器的設計初衷背道而馳的,就拿克雷計算機來說,就只支持在字邊界上以字為單位進行尋址。

  在那些不提供多種數(shù)據(jù)類型尋址方式的計算機上,編譯器可以提供一些模擬。例如:編譯器可以生成一些指令,當讀取一個字時,通過移位和屏蔽,來找到所想要的位置,以此來模擬在字中的半字尋址,但這會需要額外的時鐘周期,并且代碼體積會更大。

  從這點上來說,位域的效率是非常低的,在以位域來取出一個字時,它們產(chǎn)生的代碼體積最大。當你存取同一個字中的其他位域時,又需要對包含這個位域字的內(nèi)存,重新進行一遍尋址,這就是典型的以空間換時間。

  當在設計數(shù)據(jù)結構時,我們總是想用可以保存數(shù)據(jù)的最小數(shù)據(jù)類型,來達到節(jié)省空間的目的。我們有時小氣得經(jīng)常使用char和short,來存取位特域,這就像是為了節(jié)省一角錢,而花了一元錢。儲存空間上的高效,會付出在程序速度和體積上隱藏的代價。

  試想你只為一個緊湊結構分配了一小點的空間,但卻產(chǎn)生了大量的代碼來存取結構中的域,而且這段代碼還是經(jīng)常執(zhí)行的,那么,會因為非字尋址,而導致代碼運行緩慢,而且充斥了大量用于提取域的代碼,程序體積也因此增大。這些額外代碼所占的空間,會讓你前面為節(jié)省空間所做的努力付之東流。

  在高級數(shù)據(jù)結構中,特定的比特定位已不是必須的了,應在所有的域中都使用字(word),而不要操心它們所占用的空間。特別是在程序某些依賴于機器的部分,應該為字準備一個typedef,如下:

/*在這臺計算機上,int是一個字長*/
typedef word int;

  在高級結構中,對所有域都使用字有如下好處:

  a.. 對其他計算機架構的可移植性

  b.. 編譯器可能生成最快的代碼

  c.. 處理器可能最快地訪問到所需內(nèi)存

  d.. 絕對沒有結構對齊的意外發(fā)生

  必須也承認,在某些時候,是不能做到全部使用字的。例如,有一個很大的結構,但不會被經(jīng)常存取,如果使用了數(shù)千個字的話,體積將會增大25%,但使用字通常會節(jié)省空間、提高執(zhí)行速度,而且更具移植性。

  以下是我們的結論:

  書寫跨平臺移植的代碼,其實是件簡單的事情。最基本的規(guī)則是,盡可能地隱藏機器字長的細節(jié),用非常精確的數(shù)據(jù)元素位大小來映射物理數(shù)據(jù)結構。或者像前面所建議的,為高級編程使用高級數(shù)據(jù)結構,而低級編程使用低級數(shù)據(jù)結構,當闡明高級數(shù)據(jù)結構時,對標準C的標量類型,不要作任何假設

posted on 2006-07-07 13:51 井泉 閱讀(306) 評論(0)  編輯 收藏 引用 所屬分類: c軟件工程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美日韩在线观看a三区| 一区二区91| 久久婷婷综合激情| 久久国内精品自在自线400部| 国产视频欧美| 美女精品视频一区| 老色批av在线精品| 99精品视频免费在线观看| 亚洲欧洲一区二区天堂久久 | 久久成人免费视频| 欧美一级片一区| 亚洲国产精品成人久久综合一区| 免费一级欧美片在线播放| 欧美sm极限捆绑bd| 亚洲私人黄色宅男| 欧美亚洲日本网站| 亚洲精品1区2区| 一本色道久久加勒比精品| 国产精品丝袜白浆摸在线| 久久视频在线看| 欧美高清在线精品一区| 亚洲一区二区三区高清不卡| 性欧美1819sex性高清| 亚洲国产成人porn| 99在线热播精品免费| 国产女人aaa级久久久级| 欧美风情在线观看| 国产精品hd| 欧美高清不卡| 国产精品一区亚洲| 91久久久久久| 国产麻豆精品视频| 亚洲欧洲一区二区三区在线观看| 欧美日韩国产综合视频在线观看中文 | 久久精品视频免费| 9国产精品视频| 欧美一区二区大片| 中文无字幕一区二区三区| 久久国产免费看| 一区二区电影免费在线观看| 欧美中文在线观看| 亚洲视频高清| 欧美一级网站| 亚洲欧美另类综合偷拍| 亚洲网在线观看| 亚洲国内自拍| 久久久欧美精品| 欧美影院成人| 国产精品毛片va一区二区三区| 欧美激情视频在线免费观看 欧美视频免费一| 欧美视频日韩视频在线观看| 欧美激情在线有限公司| 在线播放视频一区| 性欧美办公室18xxxxhd| 亚洲一区三区视频在线观看| 欧美激情综合在线| 欧美激情国产日韩| 国产一区清纯| 欧美在线亚洲在线| 久久久久久香蕉网| 国产毛片一区| 亚洲男人天堂2024| 性欧美videos另类喷潮| 国产精品萝li| 亚洲午夜国产成人av电影男同| 在线亚洲电影| 国产精品h在线观看| 亚洲视频一区二区免费在线观看| 日韩一级在线观看| 欧美日韩在线视频观看| 99国产精品视频免费观看一公开| 一区二区三区国产精华| 久久亚洲精品伦理| 亚洲一区二区三区高清不卡| 欧美日韩亚洲综合| av成人激情| 亚洲免费网站| 国产日韩一区| 久久综合九色综合欧美狠狠| 欧美成人综合一区| 亚洲美女区一区| 欧美日韩成人在线视频| 亚洲午夜精品一区二区三区他趣 | 国产精品久久久久毛片软件 | 久久蜜桃av一区精品变态类天堂| 国内精品久久久久久久影视蜜臀| 先锋影音一区二区三区| 欧美成人有码| 亚洲精品欧美日韩专区| 欧美色视频日本高清在线观看| 一区二区三区日韩欧美精品| 亚洲欧美韩国| 国产在线精品一区二区夜色| 久久久久久久久一区二区| 欧美大片免费| 亚洲综合清纯丝袜自拍| 国产深夜精品| 久久精品国产99国产精品| 欧美高清自拍一区| 亚洲欧美在线看| 国产午夜精品一区二区三区视频| 久久久久久免费| 亚洲毛片av| 久久婷婷国产综合精品青草| 日韩一级裸体免费视频| 国产婷婷色一区二区三区四区| 狼人天天伊人久久| 亚洲午夜羞羞片| 欧美成人午夜剧场免费观看| 午夜精品福利电影| 亚洲国产精品t66y| 国产精品免费aⅴ片在线观看| 久久久国际精品| 亚洲图片在线| 亚洲国产欧美日韩| 久久久国产精品一区二区三区| 最新中文字幕一区二区三区| 欧美日韩精品免费观看| 久久成人精品视频| 亚洲最新视频在线播放| 久久爱www| 99视频日韩| 伊人成年综合电影网| 欧美日韩中字| 久久久在线视频| 亚洲欧美不卡| 亚洲乱码精品一二三四区日韩在线 | 91久久久久久久久久久久久| 国产欧美日韩专区发布| 国产精品99一区| 欧美日韩在线播放一区二区| 免费黄网站欧美| 久久99在线观看| 欧美一区二区在线免费观看| 亚洲一区二区三| 日韩视频免费在线观看| 91久久国产精品91久久性色| 嫩草影视亚洲| 久久亚洲国产成人| 久久综合网hezyo| 欧美一区二区三区免费看| 亚洲一级黄色片| 亚洲一区二区三区视频| 一区二区三区.www| 一区二区三区欧美日韩| 一区二区三区四区蜜桃| 亚洲人成网站在线播| 亚洲欧洲另类国产综合| 亚洲精品久久久蜜桃| 亚洲久久一区| 99国内精品久久| 亚洲婷婷综合久久一本伊一区| 这里是久久伊人| 亚洲欧美色婷婷| 久久国产精品一区二区| 久久久久成人精品| 欧美国产欧美亚洲国产日韩mv天天看完整| 久久躁日日躁aaaaxxxx| 欧美成年人视频| 亚洲激情黄色| 中国女人久久久| 欧美伊人精品成人久久综合97| 久久精品视频免费| 欧美不卡在线| 国产精品va在线播放我和闺蜜| 国产精品一区免费在线观看| 国产午夜精品理论片a级大结局| 国产日韩欧美在线播放| **网站欧美大片在线观看| 亚洲精品婷婷| 亚洲欧美国产不卡| 久久久久九九视频| 亚洲大片av| 亚洲影视在线播放| 久久综合九色综合欧美狠狠| 欧美日韩精品一区二区三区| 国产免费一区二区三区香蕉精| 在线观看日韩欧美| 亚洲性图久久| 牛人盗摄一区二区三区视频| 亚洲久久成人| 久久av二区| 欧美日韩成人综合在线一区二区| 国产九区一区在线| 亚洲激情网站| 久久电影一区| 9l国产精品久久久久麻豆| 欧美中文字幕不卡| 欧美日韩免费高清| 尤物在线精品| 亚洲欧美日韩在线播放| 亚洲国产精品第一区二区| 亚洲欧美国产三级| 欧美日韩国产a| 黄色av成人| 欧美一区二区三区日韩| 亚洲精品久久7777| 葵司免费一区二区三区四区五区| 国产九九精品| 亚洲一本视频|