首先祝各位攻城獅們今天沒有bug!
現代CPU計算時一次都能裝載多個字節(如32位計算機一次裝載4字節),多字節的數值在內存中高低位的排列方式會影響所表示的數值,以int32類型的數值169756310(十六進制表示為:0x0103070f;二進制表示為:0b 00000001 00000011 00000111 00001111)為例,在內存中用4個字節存儲,4個字節的內容分別是0x01(00000001)、0x03(00000011)、0x07(00000111)、0x0f(00001111)。根據字節高低位排序方式的不同,可以分為:大端字節序(big endian)和 小端字節序(little endian)。
大端字節序
大端字節序是指一個整數的高位字節(如上例中的0x01)存儲在內存的低地址處,可以理解為數值的高位部分靠前存儲。以前面的0x0103070f為例,假如存儲在內存中的起始地址為0x12345678,則0x0103070f在內存中的存儲為:
地址0x12345678處存儲內容為:0x01(00000001)
地址0x12345679處存儲內容為:0x03(00000011)
地址0x1234567a處存儲內容為:0x07(00000111)
地址0x1234567b處存儲內容為:0x0f(00001111)
小端字節序
和大端字節序相反,小端字節序把數值的低位字節存儲在內存的低地址處,即低位部分靠前存儲,0x0103070f在內存中的存儲為:
地址0x12345678處存儲內容為:0x0f(00001111)
地址0x12345679處存儲內容為:0x07(00000111)
地址0x1234567a處存儲內容為:0x03(00000011)
地址0x1234567b處存儲內容為:0x01(00000001)
主機字節序
現代計算機大多采用小端字節序,所以小端字節序又叫主機字節序。
網絡字節序
不同的計算機可能會采用不同的字節序,甚至同一計算機上不同進程會采用不同的字節序,如JAVA虛擬機采用大端字節序,可能和采用小端字節序計算機上的其他進程不同。所以在網絡通信(或進程間通信)時,如果都按自己存儲的順序收發數據,有可能會出現一些『誤解』。比如采用大端字節序的進程按自己字節序發數據0x0103070f給一個小端字節序進程,發送的內容為:00000001 00000011 00000111 00001111。采用小端字節序的進程接收到數據后,按照小端字節序的定義,00000001是低位字節內容,00001111是高位字節內容,這樣就把0x0103070f理解成了0x0f070301。為了避免這個問題,約定數據在不同計算機之間傳遞時都采用大端字節序,也叫作網絡字節序。通信時,發送方需要把數據轉換成網絡字節序(大端字節序)之后再發送,接收方再把網絡字節序轉成自己的字節序。上面大端發給小端的例子,大端發送時不需要做處理,直接按自己的字節序發送,小端方接收時把接收到的數據轉換成小端字節序后再使用。
linux字節序轉換函數
linux在 netinet/in.h 中定義了以下4個函數:
#include <netinet/in.h> unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort);
通過名字大概就可以看出各自的作用。如 htonl 表示 host to network long,即長整型主機字節序轉為網絡字節序。下面是一個 htonl 的使用示例:
void my_htonl() { unsigned long int n1 = 0x0103070f; unsigned long int n2 = htonl(n1); printf("%08x | %08x", n1, n2); // 0103070f | 0f070301 }
0x0102070f 經過主機字節序到網絡字節序的轉換之后就成了 0x0f070301。
更多優質文章,請到 daemoncoder.com