socket 大端 小端 转换 (转)《二》
http://blog.csdn.net/kukumouse/article/details/2270356
(1)對于位域結(jié)構(gòu)中的變量來說,其長度不能跨越字節(jié),也就是說不能超過8位。當(dāng)然如果設(shè)置空白位(無名變量,僅僅用作占位的)是沒有這個(gè)限制的。如果一個(gè)字節(jié)剩下的位長度不夠一個(gè)位域,那么從下個(gè)字節(jié)開始,也可有意置某個(gè)位域從下個(gè)字節(jié)開始。例如:
struct bits4_5
{? //一個(gè)從到小的存放順序結(jié)構(gòu)體
?? unsigned : 10;? //從位15向下跳到位5
?? unsigned? bit5:1;
?? unsigned bit4:1;
};
例二:
struct xx
{
?? unsigned a:4;
?? unsigned :2;
?? unsigned b:4; // 從第二個(gè)字節(jié)開始
};
?
(2)不同的編譯器結(jié)構(gòu)存儲(chǔ)的方式不一樣相同,這個(gè)同不同的機(jī)器內(nèi)存中存放變量的字節(jié)序不同一個(gè)道理。我們知道,關(guān)于字節(jié)序有大端和小端之分。一般來說,Intel處理器使用的是小端(little endian),Moto處理器使用的是大端(記憶中好像就Intel的用小端,其它的基本上都是大端)。小端和大端的區(qū)別在于,內(nèi)存對于變量的存放規(guī)則不同。對于小端來說:低位字節(jié)存放在內(nèi)存中相對低地址;高位字節(jié)存放在內(nèi)存中相對高地址。示例如下:一個(gè)WORD32內(nèi)容的變量,占4個(gè)字節(jié):Byte3 Byte2 Byte1 Byte0,在內(nèi)容中存放:
?Base Address +0????? Byte0
Base Address +1????? Byte1
Base Address +2????? Byte2
Base Address +3????? Byte3
??? 類推,大端存放恰恰相反。這個(gè)主要在網(wǎng)絡(luò)處理中使用的比較多。因?yàn)榭蛻舳艘驗(yàn)槭艿讲煌奶幚砥飨拗?#xff0c;因?yàn)橐獙?shí)現(xiàn)不同機(jī)器間數(shù)據(jù)的傳遞正確性,要同一規(guī)則。我們在網(wǎng)絡(luò)中使用的是網(wǎng)絡(luò)字節(jié)序,也就是大端,所以網(wǎng)絡(luò)上發(fā)送字節(jié)序要注意,特別是建立socket時(shí)目的方的IP地址和Port的表示要進(jìn)行處理才行。可能有人會(huì)問及這里為什么名說到字節(jié)序卻沒有提及傳輸?shù)臄?shù)據(jù)。因?yàn)槲覀兇蟛糠侄际鞘褂米止?jié)流byte stream的TCP方式,所以不存在字節(jié)序問題。
??? 上面說的是字節(jié)序。除此之外,不同的編譯器存儲(chǔ)結(jié)構(gòu)(類)的方式也是不一樣的,有的是采用“從小到大的字節(jié)存儲(chǔ)順序”,有的是采用“從大到小的字節(jié)存儲(chǔ)順序”。例如下面的結(jié)構(gòu)定義:
????????????
struct bits4_5?? // 按照從小到大字節(jié)存儲(chǔ)順序
?????? {
?????????? unsigned :4; // 跳過位0—位3
?????????? unsigned bit4:1;
?????????? unsigned bit5:1;
};
struct bits4_5 // 按照從大到小字節(jié)存儲(chǔ)順序
{
?? unsigned:10;? // 從位15跳過10位至為6
?? unsigned bit5:1;
?? unsigned bit4:1;
}
下面看一個(gè)簡單的例子,主要是調(diào)試前后臺(tái)程序的時(shí)候發(fā)現(xiàn)的問題。當(dāng)時(shí)的環(huán)境為:前臺(tái)是跑在單板上的程序,其中單板上運(yùn)行的是VxWorks實(shí)時(shí)操作系統(tǒng);后臺(tái)的程序是運(yùn)行在PC機(jī)器上,前臺(tái)單板通過網(wǎng)口和后臺(tái)連在一個(gè)Hub上實(shí)現(xiàn)互通。
在后臺(tái)有結(jié)構(gòu)如下(為了不引起麻煩,修改了其中的變量名稱)typedef struct NetAddr
{
?? DWORD a:2;
?? DWORD b:2;
?? DWORD c:3;
?? DWORD d:1;
?? DWORD e:4;
?? DWORD f:4;
?? DWORD g:4;
?? DWORD h:4;
?? DWORD i:8;
}T_NetAddr;
typedef union VNetAddr
{? // 針對不同的平臺(tái)使用的地址不同
?? T_NetAddr tNetAddr;
?? DWORD dwAddr;
}T_VNetAddr;
在后臺(tái)中傳遞給前臺(tái),由于字節(jié)序不一樣,要進(jìn)行轉(zhuǎn)換,這里轉(zhuǎn)換就要求按照字節(jié)進(jìn)行調(diào)整了,這個(gè)這里就不說了,這里我們只是看看結(jié)構(gòu)體中位域的存放規(guī)則。這里我們的PC機(jī)器是按照小端進(jìn)行存放的。
在main里面我們?nèi)缦抡{(diào)用:
T_VNetAddr net;
?? net.tNetAddr.a=1;
?? net.tNetAddr.b=0;
?? net.tNetAddr.c=0;
?? net.tNetAddr.d=0;
?? net.tNetAddr.e=2;
?? net.tNetAddr.f=9;
?? net.tNetAddr.g=0;
?? net.tNetAddr.h=0;
?? net.tNetAddr.i=128;
我們可以觀察內(nèi)存中的net變量的值,各個(gè)位域的值如上面的賦值所示,存放的時(shí)候按照結(jié)構(gòu)體中定義的順序一個(gè)挨著一個(gè)順序存放(按照從小到大的地址存放順序,最前面定義的位域存放在低地址,后面定義的位域存放在高地址端):
???????????? b7 b6 b5? b4 b3 b2? b1 b0
第一個(gè)字節(jié): 0? 0? 0? 0? 0? 0? 0? 1???????? b1b0=01 對應(yīng)于位域a
第二個(gè)字節(jié)?? 1? 0? 0? 1? 0? 0? 1? 0??? b7b6b5b4=9 對應(yīng)于位域f? b3b2b1b0=2對應(yīng)e
第三個(gè)字節(jié)?? 0? 0? 0? 0? 0? 0? 0? 0
第四個(gè)字節(jié)?? 1? 0? 0? 0? 0? 0? 0? 0? b7b6b5b4b3b2b1b0=128對應(yīng)于i=128
這樣看就比較清晰了,如果我們查看一下net.dwAddr就會(huì)發(fā)現(xiàn)其值為0x80009201,為什么吶?
結(jié)構(gòu)體存放內(nèi)部位域的順序是按照小端,前面定義的位域存放在低地址,這樣依次從前到后存放的地址是由低向高的存放。讀取DWORD類型的變量的時(shí)候,按照小端,地位字節(jié)存放在低地址,高位字節(jié)存放在高地址的規(guī)則,DWORD類型的dwAddr的字節(jié)排列如下:
第四個(gè)字節(jié)??? 第三個(gè)字節(jié)??? 第二個(gè)字節(jié)?? 第一個(gè)字節(jié)
80????????????? 00??????????? 92??????????? 01
沒有問題!!!
注意:千萬不要誤以為是:01920080(從前往后讀)。
-------------------------------------------------------
最近看到網(wǎng)上的一篇文章,寫的是關(guān)于大端小端互相轉(zhuǎn)換的問題。其中定義了這樣一個(gè)宏
#define sw16(x) \
? ? ((short)( \
? ?? ???(((short)(x) & (short)0x00ffU) << 8 ) | \
? ?? ???(((short)(x) & (short)0xff00U) >> 8 ) ))
這里實(shí)現(xiàn)的是一個(gè)交換兩個(gè)字節(jié)順序。
不知哪位能解釋一下這個(gè),小弟實(shí)在是看不懂。先謝謝了!
--------
假設(shè)x=0xaabb
(short)(x) & (short)0x00ffU) 與將16位數(shù)高8位置0? ?成了0x00bb 然后<<8 向左移8位后 低8位變成了高8位 低8位補(bǔ)0??結(jié)果為 0xbb00
(((short)(x) & (short)0xff00U) >> 8 ) )) 恰好相反 得到的結(jié)果為 0x00aa
兩個(gè)結(jié)果再 或一下 0xbb00 | 0x00aa 就成了 0xbbaa
------------------------------------------------------------
在網(wǎng)絡(luò)傳輸時(shí),將long類型先轉(zhuǎn)化為byte數(shù)組,步驟如下:
?
long l;
byte[] b;
b[0]=(byte)(l>>>24);
b[1]]=(byte)(l>>>16);
b[2]]=(byte)(l>>>8);
b[3]]=(byte)(l);
此時(shí),b[]中就按照網(wǎng)絡(luò)字節(jié)順序(大端法,即l的高位數(shù)據(jù)存放在byte[]的低位地址,因?yàn)榈刂肥?/strong> 從低向高發(fā)展的)存放著4個(gè)bytes的數(shù)據(jù) 使用OutputStream的public void write(byte[]?b,int?off,int?len)方法來向Socket寫字節(jié)流 ,寫byte[0]至byte[3]的字節(jié)。?
java.io
Class OutputStream
write
public abstract void write(int?b)throws IOExceptionSubclasses of OutputStream must provide an implementation for this method.
?
write
public void write(byte[]?b,int?off,int?len)throws IOExceptionThe write method of OutputStream calls the write method of one argument on each of the bytes to be written out. Subclasses are encouraged to override this method and provide a more efficient implementation.
If b is null, a NullPointerException is thrown.
If off is negative, or len is negative, or off+len is greater than the length of the array b, then an IndexOutOfBoundsException is thrown.
?
------關(guān)于網(wǎng)絡(luò)、主機(jī)字節(jié)順序的文章
http://www-128.ibm.com/developerworks/cn/java/l-datanet/index.html
?
主機(jī)和網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換
最近使用C#進(jìn)行網(wǎng)絡(luò)開發(fā),需要處理ISO8583報(bào)文,由于其中有些域是數(shù)值型的,于是在傳輸?shù)臅r(shí)候涉及到了字節(jié)序的轉(zhuǎn)換。字節(jié)順序是指占內(nèi)存多于一個(gè)字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序,通常有兩種字節(jié)順序,根據(jù)他們所處的位置我們分別稱為主機(jī)節(jié)序和網(wǎng)絡(luò)字節(jié)序。
通常我們認(rèn)為網(wǎng)絡(luò)字節(jié)序?yàn)闃?biāo)準(zhǔn)順序,封包的時(shí)候,將主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序,拆包的時(shí)候要將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序。原以為還要自己寫函數(shù),其實(shí)網(wǎng)絡(luò)庫已經(jīng)提供了。
主機(jī)到網(wǎng)絡(luò):short/int/long IPAddress.HostToNetworkOrder(short/int/long)
網(wǎng)絡(luò)到主機(jī):short/int/long IPAddress.NetworkToHostOrder(short/int/long)
?
主機(jī)字節(jié)序指低字節(jié)數(shù)據(jù)存放在內(nèi)存低地址處,高字節(jié)數(shù)據(jù)存放在內(nèi)存高地址處,如:
int x=1;? ? //此時(shí)x為主機(jī)字節(jié)序:[1][0][0][0] 低位到高位
int y=65536 //此時(shí)y為主機(jī)字節(jié)序:[0][0][1][0] 低位到高位
我們通過主機(jī)到網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換函數(shù)分別對x和y進(jìn)行轉(zhuǎn)換得到他們對應(yīng)的網(wǎng)絡(luò)字節(jié)序值,網(wǎng)絡(luò)節(jié)序是高字節(jié)數(shù)據(jù)存放在低地址處,低字節(jié)數(shù)據(jù)存放在高地址處,如:
int m=IPAddress.HostToNetworkOrder(x);
//此時(shí)m為主機(jī)字節(jié)序:[0][0][0][1] 高位到低位
int n=IPAddress.HostToNetworkOrder(y);
//此時(shí)n為主機(jī)字節(jié)序:[0][1][0][0] 高位到低位
?
經(jīng)過轉(zhuǎn)換以后,我們就可以通過
byte[]btValue=BitConverter.GetBytes(m);
得到一個(gè)長度為4的byte數(shù)組,然后將這個(gè)數(shù)組設(shè)置到報(bào)文的相應(yīng)位置發(fā)送出去即可。
同樣,收到報(bào)文后,可以將報(bào)文按域拆分,得到btValue,使用
int m=BitConverter.ToInt32(btValue,0);//從btValue的第0位開始轉(zhuǎn)換
得到該域的值,此時(shí)還不能直接使用,應(yīng)該再用網(wǎng)絡(luò)到主機(jī)字節(jié)序的轉(zhuǎn)換函數(shù)進(jìn)行轉(zhuǎn)換:
int x=IPAddress.NetworkToHostOrder(m);
這時(shí)得到的x才是報(bào)文中的實(shí)際值。
?
?
?
---------------------------------------------------
也談字節(jié)序問題
http://bigwhite.blogbus.com/logs/2005/09/
一次Sun SPARC到Intel X86的平臺(tái)移植讓我們的程序遭遇了“字節(jié)序問題”,既然遇到了也就不妨深入的學(xué)習(xí)一下。
一、字節(jié)序定義
字節(jié)序,顧名思義字節(jié)的順序,再多說兩句就是大于一個(gè)字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序(一個(gè)字節(jié)的數(shù)據(jù)當(dāng)然就無需談順序的問題了)。
其實(shí)大部分人在實(shí)際的開發(fā)中都很少會(huì)直接和字節(jié)序打交道。唯有在跨平臺(tái)以及網(wǎng)絡(luò)程序中字節(jié)序才是一個(gè)應(yīng)該被考慮的問題。
在所有的介紹字節(jié)序的文章中都會(huì)提到字節(jié)序分為兩類:Big-Endian和Little-Endian。引用標(biāo)準(zhǔn)的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。
b) Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端。
c) 網(wǎng)絡(luò)字節(jié)序:TCP/IP各層協(xié)議將字節(jié)序定義為Big-Endian,因此TCP/IP協(xié)議中使用的字節(jié)序通常稱之為網(wǎng)絡(luò)字節(jié)序。
其實(shí)我在第一次看到這個(gè)定義時(shí)就很糊涂,看了幾個(gè)例子后也很是朦朧。什么高/低地址端?又什么高低位?翻閱了一些資料后略有心得。
二、高/低地址與高低字節(jié)
首先我們要知道我們C程序映像中內(nèi)存的空間布局情況:在《C專家編程》中或者《Unix環(huán)境高級(jí)編程》中有關(guān)于內(nèi)存空間布局情況的說明,大致如下圖:
----------------------- 最高內(nèi)存地址 0xffffffff
?|?棧底
?.
?.????????????? 棧
?.
??棧頂
-----------------------
?|
?|
/|/
NULL (空洞)?
/|/
?|
?|
-----------------------
??????????????? 堆
-----------------------
未初始化的數(shù)據(jù)
----------------(統(tǒng)稱數(shù)據(jù)段)
初始化的數(shù)據(jù)
-----------------------
正文段(代碼段)
----------------------- 最低內(nèi)存地址 0x00000000
以上圖為例如果我們在棧上分配一個(gè)unsigned char buf[4],那么這個(gè)數(shù)組變量在棧上是如何布局的呢[注1]?看下圖:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
現(xiàn)在我們弄清了高低地址,接著我來弄清高/低字節(jié),如果我們有一個(gè)32位無符號(hào)整型0x12345678(呵呵,恰好是把上面的那4個(gè)字節(jié)buf看成一個(gè)整型),那么高位是什么,低位又是什么呢?其實(shí)很簡單。在十進(jìn)制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進(jìn)制也是如此。就拿 0x12345678來說,從高位到低位的字節(jié)依次是0x12、0x34、0x56和0x78。
高低地址和高低字節(jié)都弄清了。我們再來回顧一下Big-Endian和Little-Endian的定義,并用圖示說明兩種字節(jié)序:
以unsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲(chǔ)情況,我們可以用unsigned char buf[4]來表示value:
Big-Endian: 低地址存放高位,如下圖:
棧底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
棧頂 (低地址)
Little-Endian: 低地址存放低位,如下圖:
棧底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
---------------
棧頂 (低地址)
在現(xiàn)有的平臺(tái)上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。
三、例子
測試平臺(tái): Sun SPARC Solaris 9和Intel X86 Solaris 9
我們的例子是這樣的:在使用不同字節(jié)序的平臺(tái)上使用相同的程序讀取同一個(gè)二進(jìn)制文件的內(nèi)容。
生成二進(jìn)制文件的程序如下:
/* gen_binary.c */
int main() {
??????? FILE??? *fp = NULL;
??????? int???? value = 0x12345678;
??????? int???? rv = 0;
??????? fp = fopen("temp.dat", "wb");
??????? if (fp == NULL) {
??????????????? printf("fopen error/n");
??????????????? return -1;
??????? }
??????? rv = fwrite(&value, sizeof(value), 1, fp);
??????? if (rv != 1) {
??????????????? printf("fwrite error/n");
??????????????? return -1;
??????? }
??????? fclose(fp);
??????? return 0;
}
讀取二進(jìn)制文件的程序如下:
int main() {
??????? int???????????? value?? = 0;
??????? FILE?????????*fp???? = NULL;
??????? int???????????? rv????? = 0;
??????? unsigned??????? char buf[4];
??????? fp = fopen("temp.dat", "rb");
??????? if (fp == NULL) {
??????????????? printf("fopen error/n");
??????????????? return -1;
??????? }
??????? rv = fread(buf, sizeof(unsigned char), 4, fp);
??????? if (rv != 4) {
??????????????? printf("fread error/n");
??????????????? return -1;
??????? }
??????? memcpy(&value, buf, 4); // or value = *((int*)buf);
??????? printf("the value is %x/n", value);
??????? fclose(fp);
??????? return 0;
}
測試過程:
(1) 在SPARC平臺(tái)下生成temp.dat文件
在SPARC平臺(tái)下讀取temp.dat文件的結(jié)果:
the value is 12345678
在X86平臺(tái)下讀取temp.dat文件的結(jié)果:
the value is 78563412
(1) 在X86平臺(tái)下生成temp.dat文件
在SPARC平臺(tái)下讀取temp.dat文件的結(jié)果:
the value is 78563412
在X86平臺(tái)下讀取temp.dat文件的結(jié)果:
the value is 12345678
[注1]
buf[4]在棧的布局我也是通過例子程序得到的:
int main() {
??????? unsigned char buf[4];
??????? printf("the buf[0] addr is %x/n", buf);
??????? printf("the buf[1] addr is %x/n", &buf[1]);
??????? return 0;
}
output:
SPARC平臺(tái):
the buf[0] addr is ffbff788
the buf[1] addr is ffbff789
X86平臺(tái):
the buf[0] addr is 8047ae4
the buf[1] addr is 8047ae5
兩個(gè)平臺(tái)都是buf[x]所在地址高于buf[y] (x > y)。
----------------------------------------------------
一、大端模式&小端模式
所謂的“大端模式”,是指數(shù)據(jù)的低位(就是權(quán)值較小的后面那幾位)保存在內(nèi)存的高地址中,而數(shù)據(jù)的高位,保存在內(nèi)存的低地址中,這樣的存儲(chǔ)模式有點(diǎn)兒類似于把數(shù)據(jù)當(dāng)作字符串順序處理:地址由小向大增加,而數(shù)據(jù)從高位往低位放;
所謂的“小端模式”,是指數(shù)據(jù)的低位保存在內(nèi)存的低地址中,而數(shù)據(jù)的高位保存在內(nèi)存的高地址中,這種存儲(chǔ)模式將地址的高低和數(shù)據(jù)位權(quán)有效地結(jié)合起來,高地址部分權(quán)值高,低地址部分權(quán)值低,和我們的邏輯方法一致。
如果將一個(gè)32位的整數(shù)0x12345678 存放到一個(gè)整型變量(int)中,這個(gè)整型變量采用大端或者小端模式在內(nèi)存中的存儲(chǔ)由下表所示。為簡單起見,本文使用OP0表示一個(gè)32位數(shù)據(jù)的最高字節(jié)MSB(Most Significant Byte),使用OP3表示一個(gè)32位數(shù)據(jù)最低字節(jié)LSB(Least Significant Byte)。??
地址偏移??????? 大端模式?????? 小端模式
0x00?????????? 12(OP0)????? 78(OP3)
0x01?????????? 34(OP1)????? 56(OP2)
0x02?????????? 56(OP2)????? 34(OP1)
0x03?????????? 78(OP3)????? 12(OP0)
小端:較高的有效字節(jié)存放在較高的存儲(chǔ)器地址,較低的有效字節(jié)存放在較低的存儲(chǔ)器地址。
大端:較高的有效字節(jié)存放在較低的存儲(chǔ)器地址,較低的有效字節(jié)存放在較高的存儲(chǔ)器地址。
采用大小模式對數(shù)據(jù)進(jìn)行存放的主要區(qū)別在于在存放的字節(jié)順序,大端方式將高位存放在低地址,小端方式將高位存放在高地址。采用大端方式進(jìn)行數(shù)據(jù)存放符合人類的正常思維,而采用小端方式進(jìn)行數(shù)據(jù)存放利于計(jì)算機(jī)處理。到目前為止,采用大端或者小端進(jìn)行數(shù)據(jù)存放,其孰優(yōu)孰劣也沒有定論。
下面這段代碼可以用來測試一下你的編譯器是大端模式還是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址單元
x1=((char*)&x)[1]; //高地址單元
若x0=0x11,則是大端; 若x0=0x22,則是小端......
上面的程序還可以看出,數(shù)據(jù)尋址時(shí),用的是低位字節(jié)的地址
二、主機(jī)序&網(wǎng)絡(luò)序
不同的 CPU 有不同的字節(jié)序類型這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序這個(gè)叫做主機(jī)序,最常見的有兩種:
1、Little endian :將低序字節(jié)存儲(chǔ)在起始地址
2、Big endian :將高序字節(jié)存儲(chǔ)在起始地址
網(wǎng)絡(luò)字節(jié)順序是TCP/IP中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體的CPU類型、操作系統(tǒng)等無關(guān),從而可以保證數(shù)據(jù)在不同主機(jī)之間傳輸時(shí)能夠被正確解釋。網(wǎng)絡(luò)字節(jié)順序采用big endian排序方式。
為了進(jìn)行轉(zhuǎn)換 bsd socket提供了轉(zhuǎn)換的函數(shù) 有下面四個(gè):
htons 把unsigned short類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
htonl 把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
ntohs 把unsigned short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
ntohl 把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
在使用little endian的系統(tǒng)中,這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換
在使用big endian類型的系統(tǒng)中,這些函數(shù)會(huì)定義成空宏
同樣,在網(wǎng)絡(luò)程序開發(fā)時(shí),或是跨平臺(tái)開發(fā)時(shí),也應(yīng)該注意保證只用一種字節(jié)序,不然兩方的解釋不一樣就會(huì)產(chǎn)生BUG。
注:
1、網(wǎng)絡(luò)與主機(jī)字節(jié)轉(zhuǎn)換函數(shù):htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
2、不同的CPU上運(yùn)行不同的操作系統(tǒng),字節(jié)序也是不同的,參見下表:
處理器???????????? 操作系統(tǒng)???? 字節(jié)排序
Alpha?????????????????? 全部????? Little endian
HP-PA??????????????????? NT?????? Little endian
HP-PA?????????????????? UNIX???? Big endian
Intelx86??????????????? 全部???? Little endian <-----x86系統(tǒng)是小端字節(jié)序系統(tǒng)
Motorola680x()????????? 全部??? Big endian
MIPS???????????????????? NT?????? Little endian
MIPS??????????????????? UNIX??? Big endian
PowerPC????????????????? NT???? Little endian
PowerPC???????????????? 非NT??? Big endian?? <-----PPC系統(tǒng)是大端字節(jié)序系統(tǒng)
RS/6000???????????????? UNIX??? Big endian
SPARC?????????????????? UNIX??? Big endian
IXP1200 ARM核心???????? 全部????? Little endian
下面是一個(gè)檢驗(yàn)本機(jī)字節(jié)序的簡便方法:
//判斷本機(jī)的字節(jié)序
//返回true表為小段序。返回false表示為大段序
bool am_little_endian ()
{
unsigned short i=1;
return (int)*((char *)(&i)) ? true : false;
}
int main()
{
?? if(am_little_endian())
{
???????? ?? printf("本機(jī)字節(jié)序?yàn)樾《涡?\n");
}
else
{
????????? printf("本機(jī)字節(jié)序?yàn)榇蠖涡?\n");
}
??????? return 0;
}
三、入棧地址高低問題
堆棧是在內(nèi)存中指定的一段特殊存儲(chǔ)區(qū),存起始單元的地址叫棧底,當(dāng)前存儲(chǔ)單元地址叫棧頂,堆棧存儲(chǔ)區(qū)一旦指定,棧底就固定不變了,而棧頂是隨入棧、出棧操作呈動(dòng)態(tài)。而不同機(jī)型的堆棧設(shè)計(jì),有兩種情況:一是每入棧一個(gè)數(shù),棧頂?shù)刂芳?,每出棧一個(gè)數(shù),棧頂?shù)刂窚p1,即堆棧區(qū)是由內(nèi)存的低地址向高地址。另一種是每入棧一個(gè)數(shù),棧頂?shù)刂窚p1,每出棧一個(gè)數(shù),棧頂?shù)刂芳?,即堆棧區(qū)是由內(nèi)存的高地址向低地址。高地址、低地址是相對而言,即相對地址編碼的大小而言。
===============================================================
參考地址:
http://blog.csdn.net/fatshaw/article/details/5690073
http://hi.baidu.com/%C2%ED%D0%C2%CC%CE/blog/item/b3d8267b89d8cae62f73b35d.html
?
總結(jié)
以上是生活随笔為你收集整理的socket 大端 小端 转换 (转)《二》的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利润分配年末有余额吗
- 下一篇: linux svn安装