摘要:本文主要向大家介紹了C/C++知識點之詳解C語言的htons函數,通過具體的內容向大家展示,希望對大家學習C/C++知識點有所幫助。
本文主要向大家介紹了C/C++知識點之詳解C語言的htons函數,通過具體的內容向大家展示,希望對大家學習C/C++知識點有所幫助。
在Linux和Windows網絡編程時需要用到htons和htonl函數,用來將主機字節順序轉換爲網絡字節順序。
在Intel機器下,執行以下程序
int main()
{
printf("%d /n",htons(16));
return 0;
}
得到的結果是4096,初一看感覺很怪。
解釋如下,數字16的16進製表示爲0x0010,數字4096的16進製表示爲0x1000。 由於Intel機器是小尾端,存儲數字16時實際順序爲1000,存儲4096時實際順序爲0010。因此在發送網絡包時爲了報文中數據爲0010,需要經過htons進行字節轉換。如果用IBM等大尾端機器,則沒有這種字節順序轉換,但爲了程序的可移植性,也最好用這個函數。
另外用注意,數字所佔位數小於或等於一個字節(8 bits)時,不要用htons轉換。這是因爲對於主機來說,大小尾端的最小單位爲字節(byte)。
什麼是大端模式(big-endian),爲什麼使用大端模式(big-endian)。
uint16_t htons(uint16_t hostshort);
htons的功能:將一個無符號短整型數值轉換爲網絡字節序,即大端模式(big-endian)
參數u_short hostshort: 16位無符號整數
返回值:TCP / IP網絡字節順序
htons 是把你機器上的整數轉換成“網絡字節序”, 網絡字節序是 big-endian,也就是整數的高位字節存放在內存的低地址處。 而我們常用的 x86 CPU (intel, AMD) 電腦是 little-endian,也就是整數的低位字節放在內存的低字節處。舉個例子吧。假定你的port是0x1234,在網絡字節序裏 這個port放到內存中就應該顯示成addr addr+1,也就是:0x12 0x34;而在x86電腦上,0x1234放到內存中實際是:addr addr+1,也就是:0x34 0x12。htons 的用處就是把實際內存中的整數存放方式調整成“網絡字節序”的方式。
第一個問題:爲什麼使用兩個字節,也就是16位來存儲。
這個簡單一些,因爲一個字節只能存儲8位2進制數,而計算機的端口數量是65536個,也就是2^16,兩個字節。
第二個爲題:爲什麼計算機需要大端模式和小端模式?
小端模式 :強制轉換數據不需要調整字節內容,1、2、4字節的存儲方式一樣。
大端模式 :符號位的判定固定爲第一個字節,容易判斷正負。
big endian:大尾端,也稱大端(高位)優先存儲。
little endian:小尾端,也稱小端(低位)優先存儲。
如下00000000 00000000 00000000 00000001的存儲
大尾端: 00000000 00000000 00000000 00000001
addr+0 addr+1 addr+2 addr+3 //先存高有效位(在低地址)
小尾端: 00000001 00000000 00000000 00000000
addr+0 addr+1 addr+2 addr+3 //先存低有效位(在低地址)
故要判斷機器的體系結構是大尾端還是小尾端,以下程序可以完成任務:
#include <stdio.h>
int main()
{
int tt = 1;
char *c = (char*)(&tt);
if(*c == 1)
{
printf("litte endian\n");
}
else
{
printf("big endian\n");
}
return 0;
}
大小尾端數據間的相互轉換
/*
usage: to convert between the form of big-endian and little-endian
author: ydzhang
date: 2008年12月6日20:23:48
*/
#include <stdio.h>
typedef unsigned int u32;
typedef unsigned short u16;
#define BSWAP_16(x) \
(u16) ( ((((u16)(x) & 0x00ff)) << 8) \
| (((u16)(x) & 0xff00) >> 8) )
u16 bswap_16(u16 x)
{
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
u32 bswap_32(u32 x)
{
return ((x & 0x000000ff) << 24) |
((x & 0x0000ff00) << 8) |
((x & 0x00ff0000) >> 8) |
((x & 0xff000000) >> 24);
}
int main()
{
u16 num_16 = 0x1234;
u32 num_32 = 0x12345678;
printf("%x\n", bswap_16(num_16));
printf("%x\n", BSWAP_16(num_16));
printf("%x\n", bswap_32(num_32));
return 0;
}