一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

long long 類型的網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換

 水底の小魚(yú) 2009-05-31

做過(guò)socket的都知道網(wǎng)絡(luò)字節(jié)轉(zhuǎn)換的事情,網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)是純字節(jié)流,沒(méi)有類型信息,從低地址開(kāi)始傳遞;網(wǎng)絡(luò)字節(jié)序通常為大端的,即先傳遞高字節(jié),因此和大端的本地字節(jié)存儲(chǔ)順序一致,和小端的則截然相反。為了數(shù)據(jù)的一致性,就要把本地的數(shù)據(jù)轉(zhuǎn)換成網(wǎng)絡(luò)上使用的格式,然后發(fā)送出去,接收的時(shí)候也是一樣的,經(jīng)過(guò)轉(zhuǎn)換然后才去使用這些數(shù)據(jù)?;镜膸?kù)函數(shù)中提供了這樣的可以進(jìn)行字節(jié)轉(zhuǎn)換的函數(shù),如和htons( ) htonl( ) ntohs( ) ntohl( ),這里n表示network,h表示hosthtons( ) htonl( )用于本地字節(jié)向網(wǎng)絡(luò)字節(jié)轉(zhuǎn)換的場(chǎng)合,s表示short,即對(duì)2字節(jié)操作,l表示long即對(duì)4字節(jié)操作。同樣ntohs( )ntohl( )用于網(wǎng)絡(luò)字節(jié)向本地格式轉(zhuǎn)換的場(chǎng)合。隨著c99標(biāo)準(zhǔn)的推行,我們偉大的c中增加了新的類型long long int ,unsigned long long int,都是64位的,怎么辦?不轉(zhuǎn)肯定是不行,就得自己想辦法把它轉(zhuǎn)了。當(dāng)然有很多方法,我這里想使用一種類比的解決方法,看看如何舉一反三。

一、字節(jié)序定義字節(jié)序,顧名思義字節(jié)的順序,再多說(shuō)兩句就是大于一個(gè)字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序。其實(shí)大部分人在實(shí)際的開(kāi)發(fā)中都很少會(huì)直接和字節(jié)序打交道。唯有在跨平臺(tái)以及網(wǎng)絡(luò)程序中字節(jié)序才是一個(gè)應(yīng)該被考慮的問(wèn)題。一次Sun SPARCIntel X86的平臺(tái)移植讓我們的程序遭遇了“字節(jié)序問(wèn)題”。

在所有的介紹字節(jié)序的文章中都會(huì)提到字節(jié)序分為兩類:Big-EndianLittle-Endian。引用標(biāo)準(zhǔn)的Big-EndianLittle-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é)序。

二、高/低地址與高低字節(jié)首先我們要知道我們C程序映像中內(nèi)存的空間布局情況:在《C專家編程》中或者《Unix環(huán)境高級(jí)編程》中有關(guān)于內(nèi)存空間布局情況的說(shuō)明,大致如下圖:
----------------------- 最高內(nèi)存地址 0xffffffff
。。。。。。
| 棧底
.
.                      
棧頂
-----------------------
|
|
NULL (空洞)
/|\
-----------------------

-----------------------
未初始化的數(shù)據(jù)
----------------------         (統(tǒng)稱數(shù)據(jù)段)
初始化的數(shù)據(jù)
-----------------------
正文段(代碼段)
----------------------- 最低內(nèi)存地址 0x00000000
以上圖為例如果我們?cè)跅I戏峙湟粋€(gè)unsigned char buf[4],那么這個(gè)數(shù)組變量在棧上是如何布局的呢?看下圖:
棧底(高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂(低地址)

現(xiàn)在我們弄清了高低地址,接著我來(lái)弄清高/低字節(jié),如果我們有一個(gè)32位無(wú)符號(hào)整型0x12345678(呵呵,恰好是把上面的那4個(gè)字節(jié)buf看成一個(gè)整型),那么高位是什么,低位又是什么呢?其實(shí)很簡(jiǎn)單。在十進(jìn)制中我們都說(shuō)靠左邊的是高位,靠右邊的是低位,在其他進(jìn)制也是如此。就拿0x12345678來(lái)說(shuō),從高位到低位的字節(jié)依次是0x12、0x34、0x560x78。
高低地址和高低字節(jié)都弄清了。我們?cè)賮?lái)回顧一下Big-EndianLittle-Endian的定義,并用圖示說(shuō)明兩種字節(jié)序:
unsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲(chǔ)情況,我們可以用unsigned char buf[4]來(lái)表示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)上IntelX86采用的是Little-Endian,而像SunSPARC采用的就是Big-Endian。

三、網(wǎng)絡(luò)字節(jié)序的轉(zhuǎn)換假設(shè)對(duì)于little endianIA-32架構(gòu)上面的Linux,首先考慮網(wǎng)絡(luò)字節(jié)轉(zhuǎn)換的結(jié)果與原來(lái)有什么不同,如 int a = 0x12345678,b = htnla),那么就應(yīng)該是0x78563412。如果是 short c = 0x1234,short d = 0x5678e = htons(c),f = htons(d),這樣e=0x3412,f=0x7856,如果能把ef調(diào)換一下組合放在一起,不就是一個(gè)整型aa=0x12345678)轉(zhuǎn)換之后的值么?實(shí)驗(yàn)的代碼如下:
#include <stdio.h>
struct ST{
    short val1;
    short val2;
};
union U{
    int val;
    struct ST st;
};

int main(void)
{
    int a = 0;
    union U u1, u2;

    a = 0x12345678;
    u1.val = a;
    printf("u1.val is 0x%x\n", u1.val);
    printf("val1 is 0x%x\n", u1.st.val1);
    printf("val2 is 0x%x\n", u1.st.val2);
    printf("after first convert is: 0x%x\n", htonl(u1.val));
    u2.st.val2 = htons(u1.st.val1);
    u2.st.val1 = htons(u1.st.val2);
    printf("after second convert is: 0x%x\n", u2.val);
    return 0;
}
輸出結(jié)果:
u1.val is 0x12345678
val1 is 0x5678
val2 is 0x1234
after first convert is: 0x78563412
after second convert is: 0x78563412

按照這種想法我們實(shí)現(xiàn)long long int64bit)類型,把它分割成兩個(gè)int32bit),然后分別使用htonl(),分別轉(zhuǎn)換,然后再將兩種int交換順序重新組合,即實(shí)現(xiàn)了整個(gè)64位的八個(gè)字節(jié)的翻轉(zhuǎn)。
代碼如下:
#include <stdio.h>
struct ST{
    int val1;
    int val2;
};
union test {
    long long int val;
    struct ST st;
};

int main(void)
{
    long long int a;
    union test u1, u2;

    a = 0x7654321087654321LL;
    u1.val = a;
    u2.st.val2 = htonl(u1.st.val1);
    u2.st.val1 = htonl(u1.st.val2);
    printf("val1 is 0x%x\n", u2.st.val1);
    printf("val2 is 0x%x\n", u2.st.val2);
    printf("u1.val     is    : 0x%llx\n", u1.val);
    printf("after convert is : 0x%llx\n", u2.val);

    return 0;
}
執(zhí)行結(jié)果:
val1 is 0x10325476
val2 is 0x21436587
u1.val     is    : 0x7654321087654321
after convert is  : 0x2143658710325476

另外注意long long int 最大值是0x7fffffffffffffff,即7后面15個(gè)f263次方減1 unsigned long long int 最大值是0xffffffffffffffff,16個(gè)f(264次方減1)。程序中long long int可以簡(jiǎn)寫(xiě)為 long long,但是記住這是簡(jiǎn)寫(xiě),就像longlong int的簡(jiǎn)寫(xiě)。

想看數(shù)據(jù)在內(nèi)存中如何存儲(chǔ)的,就用gdb吧!使用gdb x命令,如 x /xb &a表示要察看存儲(chǔ)在變量a中的前一個(gè)字節(jié)(byte)中的數(shù)據(jù)(16進(jìn)制)。x /xw &a 就是要察看變量a中前4個(gè)字節(jié)(word)數(shù)據(jù)(16進(jìn)制)。x /xg &a 察看a開(kāi)始8個(gè)字節(jié)的數(shù)據(jù)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    精品视频一区二区三区不卡| 国产精品一区二区有码| 久热这里只有精品九九| 爽到高潮嗷嗷叫之在现观看| 国产欧美韩日一区二区三区| 国产精品香蕉一级免费| 麻豆91成人国产在线观看| 国产成人国产精品国产三级| 亚洲国产成人久久一区二区三区| 国产精品久久香蕉国产线| 欧美精品亚洲精品日韩专区| 人妻一区二区三区多毛女| 一区二区三区精品人妻| 中国美女草逼一级黄片视频| 欧美野外在线刺激在线观看| 欧美日韩校园春色激情偷拍| 日本少妇中文字幕不卡视频 | 欧美大胆美女a级视频| 狠狠做深爱婷婷久久综合| 日韩成人中文字幕在线一区 | 好吊日成人免费视频公开| 夫妻激情视频一区二区三区| 国产午夜福利片在线观看| 东京热男人的天堂一二三区 | 成人午夜视频在线播放| 狠狠做深爱婷婷久久综合| 亚洲精品熟女国产多毛| 国产又粗又黄又爽又硬的| 中文字字幕在线中文乱码二区| 亚洲做性视频在线播放| 亚洲中文字幕剧情在线播放| 国产成人av在线免播放观看av| 亚洲av熟女一区二区三区蜜桃| 欧美中文日韩一区久久| 99久久精品午夜一区| 大尺度激情福利视频在线观看| 国产永久免费高清在线精品| 国产午夜福利一区二区| 2019年国产最新视频| 成年午夜在线免费视频| 九九热视频经典在线观看|