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

Dict.CN 在線詞典, 英語學習, 在線翻譯

學??嘧髦郏瑫角跒閺?/a>

留下點回憶

常用鏈接

統(tǒng)計

積分與排名

Denoise

English study

Web技術

數(shù)據(jù)壓縮

一些連接

最新評論

編寫跨平臺的軟件入門

一,???????????? 為什么要跨平臺?

你想過把你的 Windows 上編寫的程序在 Linux 編譯運行嗎,以及在 Mac 或其他 OS 上運行等等?反過來也一樣?這就需要涉及到跨平臺編程知識。這里需要注意的是,平時很多在一個平臺運行的程序在跨平臺的時候變的不再正確。

Java 并非真的是跨平臺的開發(fā)環(huán)境,它是運行在它自己的平臺上。這里主要關注 C C++ 的跨平臺開發(fā)。

下面主要就幾個方面來討論跨平臺編程的注意事項:

1.? 字節(jié)序

2.? 字節(jié)填充

3.? 其他

二,???????????? 字節(jié)序

大家都知道計算機使用兩種字節(jié)序,一種是 little-endian ,另一種是 big-endian 。這主要是由于當前流行的 CPU 之間的差異造成的,基本上是 IBM-PowerPC 使用的大序,而其他 CPU 使用的小序。

這里先來介紹一下 little-endian big-endian 之間的具體差異。

X86 指令集合使用小序( little-endian )字節(jié)順序;這就意味著多個字節(jié)值的最重要字節(jié)在地址的最低位。小序很早就使用,因為硬件容易實現(xiàn),但和今天的制造商技術有點不同;但在第一代 IBM PC 機的 Vaxen 8086 處理器使用是它如此流行的主要原因。

看一個例子:

short example[2] = {0x0001,0x3002};

?

按照 16 進制的形式來顯示上面數(shù)據(jù)在內存中的存儲方式:

01 00 02 03

我們看到對于數(shù)組的第一個元素,高 8 位應該是 0 ,而最終存儲的時候是在低 8 位的后面。

而另一方面 PowerPC Sparc 芯片是 big-endian 的,也就是說,最重要的字節(jié)存儲在較低的地址。對于 CPU 需要額外的電路實現(xiàn)這個功能,但對于今天的處理器技術與緩存控制技術相比較顯的微不足道。使用 BIG-ENDIAN 的最大好處是在使用低級調式器時比較容易理解數(shù)據(jù)的存儲,同樣對于文件十六進制 DUMP 或網(wǎng)絡 Sniffer 顯示也是一樣的。

對于 BIG-ENDIAN ,上面的例子中內存如下表示:

00 01 03 02

這里需要注意的是:由于 BIG-ENDIAN 格式的 RAW 數(shù)據(jù)比較容易調式,如果我們有機會設計一個新的文件格式,那么使用 BIG-ENDIAN 格式,而不是根據(jù) CPU 架構來決定。

下面看幾個關于字節(jié)序的問題:

1.? Long 型指針和 char 指針之間的轉換

看下面這段代碼

unsigned long value = 0x03020100;

unsigned long *ptr = &value;

unsigned char charVal;

charVal = *(unsigned char *)ptr;

程序的含義比較簡單,主要是從一個指向 long 的指針強制轉換為一個指向 char 的指針,這里假設指針指向的是最不重要的字節(jié)地址。

在一個 little-endian 處理器上, charVal 0 ,而在一個 big-endian 處理器上, charVal 的值是 3 。這樣的問題是最難以發(fā)現(xiàn)的問題之一。

為了避免這個錯誤,使用一個臨時變量可以解決這個問題,如下:

unsigned long temp = *ptr;

charVal = (unsigned char)temp;

上面的第二行代碼就保證將在任何架構上都將最不重要的字節(jié)傳遞給 charVal ;編譯器處理具體的細節(jié)。

2.? 讀寫文件和寫網(wǎng)絡數(shù)據(jù)

在從文件讀數(shù)據(jù)或寫數(shù)據(jù)到文件的時候以及網(wǎng)絡,對于字節(jié)順序的處理一定要小心;一定記住不能將多個字節(jié)的數(shù)據(jù)寫到文件或網(wǎng)絡上;例如:

long val = 1;

int result = write(fileDes,&val,sizeof(val));

這段代碼在 little-endian big-endian 機器上執(zhí)行的結果是不一樣的,如果讀數(shù)據(jù)的時候使用如下代碼:

long val ;

int result = read(fileDes,&val,sizeof(long));

如果這兩段代碼分別位于 little-endian big-endian 機器上,那么最終得到的 val 不是 1 ,而是 0x01000000 。

解決多字節(jié)的讀寫有很多辦法,這里提供兩種。

方法 1

寫的代碼

long val = 1;

char buf[4];

buf[0] = 0xff&val;

buf[1] = (0xff00&val)>>8;

buf[2] = (0xff0000&val)>>16;

buf[3] = (0xff000000&val)>>24;

int result = write(fileDes,buf,4);

讀的代碼

long val;

char buf[4];

int result = read(fileDes,buf,4);

val = buf[0]|(buf[1]<<8)|(buf[2]<<16)|(buf[3]<<24);

3.? 運行時檢查字節(jié)順序

bool gIsBigEndian;

void InitializeEndianFlag()

{

Short one = 1;

Char *cp = (char *)&one;

If(*cp == 0)

??? gIsBigEndian = true;

else

??? gIsBigEndian = false;

return ;

}

4.? 字節(jié)交換對性能的影響

由于字節(jié)順序的問題導致在處理的時候需要進行字節(jié)交換或類似 2 中方法 1 的處理,這里稱為交換。通常情況下,做字節(jié)順序的交換并不影響,因為交換兩個字節(jié)或四個字節(jié)值只需要很少的 CPU 指令,并且完全可以在寄存器中執(zhí)行。

但如果有很多數(shù)據(jù)需要交換,例如:一個 1024*768 位圖的圖像,在這么大的循環(huán)中執(zhí)行是影響性能的。

另外對于 3 的運行時檢查字節(jié)序的代碼要查看具體的位置。如果僅僅調用一次或幾次,不會影響性能,如果對于上面的這個循環(huán)中調用,對性能的影響是顯著的,這個時候可以使用一個預編譯宏來分別處理。例如:

#ifdef BIG_ENDIAN//big-endian

#else//little-endian

#endif//BIG_ENDIAN

?

三,???????????? 字節(jié)填充

另一個寫可移植代碼的注意點是結構體的字節(jié)對齊和填充。通常,在單個平臺上,如果需要保存一個結構體到文件,那么是作為一個整體寫到文件的,如下:

struct myStruct{

char theChar;

long theLong;

};

struct myStruct foo;

foo.the Char = 1;

foo.theLong = 2;

如果我們已經(jīng)將數(shù)據(jù)按照 big-endian 進行了交換,然后直接將整個結構體寫到文件中。那么什么樣的數(shù)據(jù)會被寫到磁盤上呢?

int result = write(fileDes, &foo, sizeof(foo));

實際上我們不知道具體寫了什么數(shù)據(jù),因為我們還不知道這個代碼在什么平臺上運行;實際上上面的 code 中會將垃圾數(shù)據(jù)寫到文件里,垃圾數(shù)據(jù)多少由 foo 分配到的內存決定的。

一種可能我們認為的情況是:

?01 00 00 00 02

但我們可能得到的這樣的數(shù)據(jù):

01 f 8 00 00 00 02

甚至是:

01 e6 a7 20 00 00 00 02

這里到底發(fā)生了什么? sizeof(foo) 是編譯器和處理器依賴的。

有些處理器不能從某些位置讀或寫多個字節(jié);幾乎所有的都不能從奇數(shù)地址來讀數(shù)據(jù)。通常他們只讀那些是 sizeof value )倍數(shù)的地址;對于四個字節(jié)只能讀地址是 4 個字節(jié)的倍數(shù),對于 2 個字節(jié)的 short 只能讀兩個字節(jié)倍數(shù)的地址。如果不遵從這個字節(jié)對齊的規(guī)律,處理器會拋出一個異常并且終止程序,有些系統(tǒng)上會鎖定機器(如果發(fā)生在 kernel 中)。

有時,讀沒有對齊的數(shù)據(jù)需要花費額外的時間。例如: PowerPC 能夠讀任何偶數(shù)地址,但對于那些不能被 4 整除的地址需要耗費額外的總線周期。為了讀一個 long 數(shù)值( value )在 2 整除而不是 4 整除的地址,它將讀四個字節(jié)并包括需要讀的值的上面兩個字節(jié),拋棄 2 個字節(jié),然后讀另外四個包含 value 2 個字節(jié)的字節(jié),同樣拋棄另外兩個。這與讀 4 個字節(jié)對齊的地址相比需要多訪問一次緩存。

為了達到字節(jié)對齊的目的,編譯器會插入未命名的填充字節(jié)到結構體中。至于插入幾個字節(jié)是通過編譯器和 OS 或庫內存分配器一起決定的。

Windows VC 編譯器中,可以使用 #pragma 來指定字節(jié)對齊的方式。

總而言之,在定義結構的時候要按照字節(jié)邊界對齊來定義,一般按照 4 個字節(jié),如果不夠就需要增加填充字段。

另外對于結構體寫文件或輸出到網(wǎng)絡上,最好的辦法是按照成員來逐個寫入或發(fā)送,這可以避免將垃圾數(shù)據(jù)存放到文件中或傳輸?shù)骄W(wǎng)絡上。

?

四,???????????? 其他

下面是幾個筆者在實際編寫代碼中發(fā)生過的錯誤,這里與大家一道分析一下。

1.???????? 示例 1

for(int i = 0;i<1000;i++)

{

?? ….

}

...

for(int i = 0;i<1000;i++)

{

...

}

上面這段代碼是很普通的 C++ 代碼,但這段代碼不一定可以在所有的編譯器中都能編譯通過。主要的原因在于變量 i 的聲明。

C++ 標準說:在 for 循環(huán)內部聲明的變量在 for 結束的時候無效,因此可以連續(xù)使用再次在 for 循環(huán)中使用該記數(shù)器變量。但很不幸的是很多編譯器都提供編譯選項來讓你覺得變量是否在 for 循環(huán)以后仍然有效。 VC 中默認編譯選項 /Ze 用來指定 for 循環(huán)變量的局部性,但并非所有的編譯器都是將這個選項作為默認編譯參數(shù);所以為了能讓你的代碼可以在任意平臺編譯通過,使用 C 風格的會有保證一點;如下:

int i = 0;

for(i = 0;i<1000;i++)

{

?? ….

}

...

for(i = 0;i<1000;i++)

{

...

}

?

2.???????? 示例 2 int 型變量的使用

Int 型變量是一個奇怪的東西,它在 16 位機器上是 2 個字節(jié),在 32 位機上是 4 個字節(jié);將來可能在 64 位機上是 8 個字節(jié)。所以如果你的代碼中有對 int 的使用,而你想代碼可以在很多平臺上運行,那么一定要注意了??匆幌孪旅娴那闆r:

for(int i = 0;i<65540;i++)

{

?? ….

}

這個代碼可能在不同的平臺上得到不同的結果。如果這個代碼是在 16 位機器上運行,那么得到的結果與 32 位機器上可能不同。

同樣在使用 int 型變量寫文件和輸出到網(wǎng)絡時都要小心這個問題。最好的辦法是,在這些情況下不要使用 int 型變量; int 型變量僅僅在程序內部使用。

3.???????? 關于 Bit field 的問題

C 語法中有 bit field 的語法,可以根據(jù)需要來定義一個符號具體占用的 bit 數(shù),例如:

typedef struct tagTest
{
???char a:4;
?? char b:2;
?? char c:2;
}TagTest,*PTagTest;

實際上 tagTest 的字節(jié)數(shù)是 1 個字節(jié),成員 a 占用 4 位, b 和各占用兩位。這樣的好處是可以針對每個成員賦值而設置指定的位的值,例如:

tagTest myTest;
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;

假如你在 Windows 上是使用 VC 來編譯連接上面的程序,不管如何處理,你不會發(fā)生任何問題。但現(xiàn)在我們假設將 myTest 放入緩沖區(qū)中,然后在 MAC 機器上取出來,那么會發(fā)生什么來?看代碼:

Windows:

char buf[10];

buf[0] = myTest;

buf[2]=...

int result = send(fd,buf,10,..);

?

MAC:

char buf[10];

int ret = 0;

int result = recv(fd,buf,10,..);

PTagTest pTest = (PTagTest)&buf[0];

?

if(pTest->a == 10)

?? ret = 1;

else

??? ret = 0;

...

那么 ret 的值是什么呢?我們期望是 1 但,結果不是 1 。如果你通過調試器來觀察一下 pTest 各成員的值你發(fā)現(xiàn):

pTest->a = 6; pTest->b =2 ; pTest->c =2;

細心的讀者可能發(fā)現(xiàn)這里的問題所在,原因在于不同的編譯器對 bit field 進行了不同的處理。在 Windows 平臺上, c 被放在字節(jié)的最高兩位,而 a 被放在字節(jié)的最低 4 位,在 MAC 上正好相反。但一定要注意,這是編譯器行為,而不是數(shù)據(jù)在傳輸過程中發(fā)生了字節(jié)的位交換。在 Windows 發(fā)送到網(wǎng)絡的時候, buf[0] 的內容二進制表示為:

01 10 1010

MAC recv 之后, buf[0] 的內容仍然與上面的相同。

為了避免這個問題,請不要在寫文件或網(wǎng)絡輸出的時候使用 BIT FILED 語法,如果一定要使用請注意編譯器對位處理的區(qū)別。

n???????? 小結

其實實際工作中,大家認為自己的代碼都不需要在多個平臺上運行,而認為跨平臺編碼與自己無關;其實不然,好的編碼習慣是慢慢養(yǎng)成的,如果大家都知道這些跨平臺編碼的細節(jié),在開始寫代碼的時候就開始避免這樣的問題,一旦有一天我們的代碼需要跨平臺運行或一點我們要寫跨平臺代碼時,我們就不會無從下手,而是順其自然,因為我們已經(jīng)具備了這樣的習慣。

當然這里的介紹只是一個開始,跨平臺編碼涉及的問題還很多,由于筆者經(jīng)驗的限制不能一一描述。

?

本文參考: http://www.goingware.com/tips/getting-started/

posted on 2006-11-23 10:12 笨笨 閱讀(2304) 評論(4)  編輯 收藏 引用 所屬分類: 編碼

評論

# re: 編寫跨平臺的軟件入門 2006-11-25 15:55 Fany

謝謝,好東西啊。  回復  更多評論   

# re: 編寫跨平臺的軟件入門 2006-11-29 11:37 笨笨

謝謝  回復  更多評論   

# re: 編寫跨平臺的軟件入門 2006-12-01 23:15 xiaoE

牛人~
我還沒有入門  回復  更多評論   

# re: 編寫跨平臺的軟件入門 2007-06-13 23:54 nines

寫得比較好  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产精品黑人久久久| 国内自拍亚洲| 一区二区三区免费观看| 模特精品在线| 久久综合九色| 欧美成人精品一区二区| 美玉足脚交一区二区三区图片| 久久精品一二三| 能在线观看的日韩av| 亚洲国产91精品在线观看| 亚洲国内欧美| 夜夜嗨av一区二区三区中文字幕| 99视频一区二区| 销魂美女一区二区三区视频在线| 久久不射中文字幕| 麻豆成人综合网| 欧美日韩在线不卡一区| 国产一区二区三区在线观看免费| 在线观看国产精品网站| 一区二区三区欧美在线| 久久精品亚洲一区二区| 91久久国产精品91久久性色| 亚洲欧美成人| 麻豆精品在线视频| 国产精品久久久久影院亚瑟| 亚洲第一中文字幕| 性伦欧美刺激片在线观看| 久久综合狠狠综合久久激情| 夜夜嗨av一区二区三区四区| 久久女同精品一区二区| 欧美激情四色| 激情久久五月| 亚洲综合视频1区| 欧美成人小视频| 亚洲在线中文字幕| 欧美日韩成人一区二区三区| 黄色亚洲在线| 午夜亚洲影视| 91久久久亚洲精品| 久久久久久**毛片大全| 国产精品一区免费视频| 一本久久知道综合久久| 蜜臀久久99精品久久久久久9| 亚洲一区二区在线免费观看| 欧美日韩国产高清| 亚洲国产精品成人久久综合一区| 久久岛国电影| 亚洲一区二区在线播放| 欧美日韩一区二区三| 亚洲日本电影| 亚洲大胆av| 久久日韩精品| 黄色一区二区在线观看| 久久久99久久精品女同性| 夜夜嗨av色综合久久久综合网| 欧美成人资源| 午夜精品亚洲| 午夜视频在线观看一区| 国产精品成人一区二区三区吃奶| 夜夜嗨av一区二区三区中文字幕| 欧美大片一区二区三区| 老司机午夜精品视频| 在线成人免费观看| 久久视频在线免费观看| 久久精品动漫| 精品不卡一区| 欧美成人精品在线| 免费黄网站欧美| 亚洲美女黄网| 亚洲精品一区二区三区福利| 欧美精品福利视频| 在线亚洲一区二区| 亚洲五月婷婷| 国产一区亚洲| 免费看亚洲片| 巨乳诱惑日韩免费av| 亚洲国产色一区| 亚洲清纯自拍| 国产精品久久久久7777婷婷| 久久www成人_看片免费不卡| 久久激情视频| 亚洲欧洲一区二区三区在线观看 | 国产精品视频午夜| 香蕉久久夜色精品国产使用方法| 性久久久久久久久久久久| 国产伦精品一区二区| 久久在线视频| 欧美国产在线视频| 亚洲一区免费看| 久久www成人_看片免费不卡| 在线观看视频日韩| 亚洲精品一区二区三区婷婷月| 国产精品久久久爽爽爽麻豆色哟哟| 欧美一区二区在线看| 久久欧美中文字幕| 一区二区不卡在线视频 午夜欧美不卡在 | 国产精品看片资源| 久久男人资源视频| 欧美久久一级| 久久精品欧美| 欧美日韩国产系列| 久久久久久电影| 欧美天堂在线观看| 久久在线视频| 国产精品久久久久久久久果冻传媒| 久久人人爽人人爽爽久久| 欧美国产在线观看| 久久精品视频导航| 欧美视频国产精品| 亚洲电影免费观看高清完整版在线观看 | 久久综合一区二区| 亚洲小说区图片区| 久久综合伊人| 性视频1819p久久| 欧美日韩国产成人在线| 久久人人爽爽爽人久久久| 欧美三区免费完整视频在线观看| 欧美va亚洲va香蕉在线| 国产午夜精品久久久| 夜久久久久久| 夜夜嗨av一区二区三区四季av| 久久久999| 欧美一区国产在线| 欧美午夜不卡影院在线观看完整版免费| 久久亚洲影音av资源网| 国产精品老女人精品视频| 亚洲精品一二| 亚洲精品美女免费| 麻豆成人在线观看| 欧美大片免费观看| 亚洲二区在线观看| 久久美女性网| 欧美国产精品专区| 亚洲第一网站免费视频| 久久gogo国模啪啪人体图| 久久国产99| 国产自产在线视频一区 | 欧美+亚洲+精品+三区| 开元免费观看欧美电视剧网站| 国产女主播视频一区二区| 亚洲欧美成人一区二区在线电影| 亚洲视频www| 国产精品第一区| 亚洲欧美第一页| 性欧美xxxx视频在线观看| 欧美特黄一级| 亚洲永久免费| 久久久久国产精品一区二区| 国产欧美韩日| 久久久精品性| 欧美激情国产日韩精品一区18| 亚洲国产欧美精品| 欧美激情一区在线| 日韩视频免费在线观看| 亚洲一本视频| 国产日韩亚洲欧美综合| 久久久久久伊人| 亚洲第一在线综合网站| 亚洲精品乱码久久久久久日本蜜臀| 欧美激情第六页| 亚洲一本大道在线| 久久亚洲高清| 日韩小视频在线观看| 欧美色欧美亚洲另类七区| 午夜精品久久| 欧美成人精品高清在线播放| 日韩一区二区免费看| 国产精品一区久久久久| 久久久噜噜噜久噜久久| 亚洲精品国产精品国自产观看 | 洋洋av久久久久久久一区| 国产精品成人午夜| 欧美日韩国产综合在线| 久久精品国产精品亚洲综合| 欧美黑人国产人伦爽爽爽| 一区二区精品在线观看| 久久精品在这里| 在线午夜精品自拍| 国产一区二区精品久久91| 欧美福利一区| 久久国产精品第一页| 亚洲片在线资源| 久久精品91| 亚洲网在线观看| 亚洲福利视频网站| 国产精品另类一区| 欧美激情精品久久久久久大尺度| 亚洲男女自偷自拍| 亚洲日本久久| 欧美国产免费| 久久久久久久波多野高潮日日| 99国产精品久久久久久久久久| 好吊一区二区三区| 国产免费观看久久| 欧美日韩精品免费在线观看视频| 狂野欧美激情性xxxx| 欧美专区福利在线| 午夜精品av| 亚洲欧美激情视频| 亚洲图片你懂的|