Endian是什麼意思呢?還是讓我們先來看看下面的情況,
這是記憶體中一個WORD值中的內容,
那麼這個WORD中的值是0x1234呢,還是0x3412 ?
low byte high byte
0x12 0x34
熟悉x86彙編的人立刻就知道這個值應為0x3412,
很對,
但在一些情況下,
比如說你在SGI的機器上看到這種情況,
則正好相反,
0x1234才是正確答案,
這與CPU內部處理資料的方式有關。
這兩種處理方式都存在于不同廠商生產的CPU之中,
在上例中若此WORD值為0x3412的,
我們稱之為little-endian,
若為0x1234的,
我們稱之為big-endian,
這是兩種不同的byte orders。
MSDN中有比較精確的定義如下:
Byte Ordering Byte ordering Meaning
big-endian The most significant byte is on the left end of a word.
little-endian The most significant byte is on the right end of a word.
一般來說我們不用關心byte ordering的問題,
但若要涉及跨平臺之間的通信和資源分享,
則不得不考慮這個問題了。
也許你會說,
我永遠不會去用其他非x86的CPU,
也許是這樣,
你甚至可以不必知道我們最常用的Intel,
AMD等生產的x86的byte ordering是little-endian的,
而且按現在的裝機數量來看,
可以說世界上絕大多數CPU是little-endian的,
但多瞭解一些沒有什麼壞處,
也許有用上的一天,
實際若您要涉及到網路編程,
瞭解一些還是有所幫助的,
看完本文後您就應該知道
為何socket編程中為何要用到如 ntohl, htonl, ntohs, htons
這幾個看起來名字似乎怪怪的API了,
也很容易理解這些函數名的意義了。
假設我們要在不同byte ordering的機器之間傳輸和交換資料,
那該怎麼辦呢,
有兩個方法,
一是全部轉換成文本來傳輸(如XML使用的),
另一個方法兩方都按照某一方的byte order,
這時就涉及到了不同byte order之間相互轉換的問題
(網路傳輸標準如TCP/IP採用第二種方法並且由於歷史的原因,
byte ordering是big-endian的)。
兩種之間該如何轉換呢?
方法有很多,我們可以先看看MFC中在
處理serialize的代碼中所用的方法(List),
雖然代碼應該是高效易讀的,
但我個人並不喜歡它,
原因是我覺得這不是一種通用優美的方法.
下面列出的是我自己寫的轉換的代碼:
template F3D_INLINE T ConvertEndian(T t)
{
T tResult = 0;
for (int I = 0; I < tresult =" (t">>= 8;
}
return t Result;
}
原理非常簡單,
交換位元組順序,
我就不多說了,
當然這個寫法並不是快速的,
只是通用的(我沒條件試, 若有不對之處請指出), 若要快速的代碼,
可以在不同platform上用與platform
相關的代碼, 如在PowerPC上有 "load word byte-reversed indexed" (lwbrx)
和 "load halfword byte-reversed indexed" (lhbrx) 指令,
在x86上還可用BSWAP單個彙編指令等,
在類型上專為int16, int32寫的通用的代碼也可以比這快得多.
當然如果在byte ordering相同的情況下,
應該不必用這個轉換函數,
所以我們可以定義一個宏來處理不同的byte ordering,
也可以在運行時測試byte ordering,
下面的代碼給出了一個簡單的測試方法。
// Test for endianness.
F3D_INLINE bool IsLittleEndian(void)
{
DWORD dwTestValue = 0x12345678L;
return (*((BYTE*)&dwTestValue) == 0x78);
}
但是float比較怪,
有可能所涉及到不僅僅是byte order的問題,
因為有些平臺如Alpha不使用IEEE的浮點格式,
還得自己轉換。
當然同上,
其他的方法一是將所用的float用文本方式輸入輸出,
另一個辦法是在某些情況下可將其轉換成定點數再處理,
這裏我不再深入。
如果是讀寫第三方已經指定byte order的檔或資料流程,
比如說讀SGI的點陣圖檔格式,
則可以直接自行按指定的byte order拼起來,
不必考慮host機是何種byte ordering。
下面我給出相應的代碼:
// Read a little-endian TYPE from address
template F3D_INLINE T GetLittleEndian(const BYTE* pBuf)
{
T tResult = 0;
pBuf += sizeof(T) - 1;
for (int I = 0; I < tresult =" *pBuf" tresult =" 0;" i =" 0;" tresult =" *pBuf" i =" 0;">>= 8;
}
}
// Set a big-endian T on a address
template F3D_INLINE void SetBigEndian(BYTE* pBuf, T t)
{
pBuf += sizeof(T) - 1;
for (int I = 0; I <>>= 8;
}
}
從上文可以看出,byte order挺簡單的,
一般應用中可能也用不上,
但若您對寫跨平臺的程式有興趣,
則一定要瞭解的比較清楚才行。
以上代碼都是從實際使用的源碼中取下來的。
附:常見Processor, OS的byte ordering情況
Processor OS Order
x86 (Intel, AMD, … ) All little-endian
DEC Alpha All little-endian
HP-PA NT little-endian
HP-PA UNIX big-endian
SUN SPARC All? big-endian
MIPS NT little-endian
MIPS UNIX big-endian
PowerPC NT little-endian
PowerPC non-NT big-endian
RS/6000 UNIX big-endian
Motorola m68k All big-endian