标题：字节顺序
简介
基于X86平台的PC机是小端字节序的，而有的嵌入式平台则是大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据，在这些嵌入式平台上应该变换其存储顺序。通常我们认为，在空中传输的字节的顺序即网络字节序为标准顺序，考虑到与协议的一致以及与同类其它平台产品的互通，在程序中发数据包时，将主机字节序转换为网络字节序，收数据包处将网络字节序转换为主机字节序。
跨平台应用的不同
在本LINUX的书里介绍到INTEL的CPU使用的小端字节序 其他比MOTOROLA 
68000系列CPU使用的是大端字节序 如果不转换 将数据通过网络发出时 比如MOTOROLA发一个16位数据：0X1234 传送到INTEL时 
就被INTEL解释为0X3412 也就是4660成了13330 所以有时候需要一些函数来进行大小端字节序的转换
字节概念
关于这大小字节序的概念不是很想的明白 数据在 
内存里是具体怎么存放的形式？为什么会有CPU解释的不同？数据不是按12345678……这样的顺序一直排列的么？
如: 一个多字节值 0xFECDBA98,内存从地址100开始存放 
降序: FE | CD | BA | 98---->;对应地址100 | 101 | 102 | 103 
升序: 98 | BA | CD | FE ---->;same above 
注意,我们的书写表示法是从低字节位--->;高字节位 
内存地址生长方向为: 从左到右 由低到高(这是不变的) 
数据为: 0x98BADCFE 
降序(Big-endian)大端字节序 存储时 由左到右 
升序(Little-endian)小端字节序 存储时 由右向左
程序验证
可以自己编一个小程序验证一下(用C的数组) 
更简单的调用VC里的checkEndian()
Intel处理器的字节顺序是和DEC VAX处理器的字节顺序一致的。因此它与68000型处理器以及Internet的顺序是不同的，所以用户在使用时要特别小心以保证正确的顺序。
任何从Windows Sockets函数对IP地址和端口号的引用和传送给Windows Sockets函数的IP地址和端口号均是按照网络顺序组织的，这也包括了sockaddr_in结构这一数据类型中的IP地址域和端口域（但不包括sin_family域）。
考虑到一个应用程序通常用与“时间”服务对应的端口来和服务器连接，而服务器提供某种机制来通知用户使用另一端口。因此getservbyname()函数返回的端口号已经是网络顺序了，可以直接用来组成一个地址，而不需要进行转换。然而如果用户输入一个数，而且指定使用这一端口号，应用程序则必须在使用它建立地址以前，把它从主机顺序转换成网络顺序（使用htons()函数）。相应地，如果应用程序希望显示包含于某一地址中的端口号（例如从getpeername()函数中返回的），这一端口号就必须在被显示前从网络顺序转换到主机顺序（使用ntohs()函数）。
由于Intel处理器和Internet的字节顺序是不同的，上述的转换是无法避免的，应用程序的编写者应该使用作为Windows Sockets API一部分的标准的转换函数，而不要使用自己的转换函数代码。因为将来的Windows Sockets实现有可能在主机字节顺序与网络字节顺序相同的机器上运行。因此只有使用标准的转换函数的应用程序是可移植的。
如何手算主机字节顺序转换为网络字节顺序？
假设某16位的整数，主机字节顺序的值是21，那么它的网络字节顺序是多少？解决的步骤是：
1、将21化成二进制，二进制，如果不足16位就在其前面补0，补满16位。
21转换成二进制是：10101，在它前面补0，补满16位后就得到：
00000000 00010101
2、将这个16位二进制字符平分成两段，每段8位
0000000 000010101 == > 00000000 00010101

3、颠倒这两段的顺序，然后去掉第一个字符“1”前面的0，化成十进制就得到了网络字节顺序的值了。
00000000 00010101 颠倒后：00010101 00000000
即00 01 01 01 00 000000
去掉第一个“1”前面的0得到：10 10 10 00 00 00 0
化成十进制得到：5376
通过这个程序可以进行验证：
#include <stdio.h> 
#include <string.h> 
#include <netdb.h> 

int main(void) 
{ 
struct servent *server=NULL; 
char sername[16]= "\0"; 
char proname[4]= "\0"; 

printf("请输入服务名称："); 
gets(sername); 

printf("请输入使用的协议："); 
gets(proname); 

//如果能够通过getserbyname函数找到结果，就输出结果，否则报错 
if((server=getservbyname(sername,proname))!=NULL) 
{ 
printf("网络服务端口：\n "); 
printf("网络字节顺序值：%d\n",server->s_port); 
printf("主机字节顺序值：%d\n",ntohs(server->s_port)); 

} 
else 
{ 
printf("该服务不存在\n"); 
} 
return 0; 
} 
编译后，按提示输入ftp和tcp，就得到网络字节顺序值是5376，主机字节顺序值是21。
16位的转换函数：ntohs和htonsntohs(network to host short)是将网络字节顺序转换为主机字节顺序，返回值是一个16位的整数，即2个字节长度的整数（1字节=8位）short int，也可以写作uint16_t。htons(host to network short)是将主机字节顺序转换为网络字节顺序，返回值也是一个16位的整数short int。

32位转换函数ntohl和htonl。ntohl(network to host long)是将网络字节顺序转换为主机字节顺序，返回值是一个16位的整数，即2个字节长度的整数（1字节=8位）long int，也可以写作uint32_t。htons(host to network long)是将主机字节顺序转换为网络字节顺序，返回值也是一个16位的整数long int。 IP地址使用的是32位的无符号整数，所以，在对IP地址进行处理的时候，就需要用到32位的转换了。一个点分十进制的IP地址是192.168.0.1，还原成原来的二进制原码是：
11000000 10101000 0000000 00000 0001
这是主机字符顺序存储的值。将其按照每个字节分隔开来，即每8位分隔开来，得到：11000000 10101000 00000000 00000001 将这4段二进制编码进行完全颠倒，就得到了网络字节顺序：00000001 00000000 10101000 11000000 去掉第一个字符“1”前面无效的0，得到：10 00 00 00 01 01 01 00 01 10 00 00 0
化成十进制得到：16820416inet_addr函数可以将一个点分十进制的IP地址转换成网络字节顺序的长整形十进制值。同样的，inet_ntoa函数将网络字节顺序的长整形十进制数值的IP地址转换成点分十进制。【综合案例】将一个点分十进制的IP地址转换成它的二进制原码分析：用inet_addr函数，转换点分十进制的IP为网络字节顺序的长整型十进制数值后，再用ntohl函数将其转换成主机字节顺序的长整型整数，然后使用一个自定义函数将这个主机字节顺序的长整形整数转换成二进制。
#include <stdio.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <string.h> 

//十进制转二进制函数，参数为无符号超长整形（防止溢出） 
void dec(const unsigned long long int x) 
{ 
if(x/2>0) 
{ 
dec(x/2); 
printf("%d",x%2); 
} 
else 
{ 
printf("%d",x); 
} 
} 

int main(void) 
{ 
char ipaddr[15]= "\0"; 
unsigned long long int hostaddr=0; //主机字节IP的值 
printf("请输入IP地址："); 
gets(ipaddr); 

hostaddr=ntohl(inet_addr(ipaddr)); 
printf("IP地址的网络字节顺序的值：%ld\n",inet_addr(ipaddr)); 

//调用dec函数，为了防止溢出将hostaddr强制转换成无符号超长整形后再转换成二进制 
printf("二进制形式是：\n"); 
dec((unsigned long long int)hostaddr); 
printf("\n"); 
return 0; 
}