一、数据存储顺序:大端和小端
大端模式: 地址的增长顺序与值的增长顺序相反
小段模式: 地址的增长顺序与值的增长顺序相同
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。
我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。所以,主机字节顺序是小端模式。网络字节顺序是大端模式。
在C语言中,不同于结构体,共用体(联合体)中的几种不同类型的变量存放在同一段内存单元中。利用这一特点,可以用联合体变量判断ARM或X86环境下,存储系统是是大端还是小端模式。
#include "stdio.h" int main() { union w { int a; //4 bytes char b; //1 byte } c; c.a=1; if (c.b==1) printf("It is Little_endian!\n"); else printf("It is Big_endian!\n"); return 1; }说明:
字节序的处理
因为存在大端小端的问题,所以就要进行统一的转换。
注意字符串是不用转换的,因为一个字符正好占一字节。存储顺序不影响值。而浮点数也不用转换,因为浮点数的读取规则是在cpu中定义的,是一致的。
转换所用的函数为:
htons(),htonl(); 主机转为网络字节序,s为short , l为long
ntohs(),ntohl(); 网络转为主机字节序。
二、地址格式的转换
通常情况下,都是用点分十进制(如:202.134.23.145)来表示IP地址。是个字符串。但是程序中处理时用到的是一个二进制的值。所以要进行转换。
具体的有四个函数:
#include<stdio.h> #include<stdlib.h> #include<netinet/in.h> int main(){ //ip地址字符串 char* sa="202.30.45.11"; //记录ip地址的结构体 struct in_addr addr,ret; //是网络地址类型 in_addr_t at; //将点分十进制字符串转换为32位网络字节序的IP at=inet_addr(sa); //十六进制输出 printf("inet_addr:0x%x \n",at); //将点分十进制字符串转换为32位主机字节序,与网络字节序应该是反过来的 printf("inet_network:0x%x \n",inet_network(sa)); //结构体中记录IP地址的数据成员 addr.s_addr=at; //网络字节序转换为点分十进制数 printf("inet_ntoa:%s \n",inet_ntoa(addr)); //点分十进制数转换为网络字节序,参数为结构体 inet_aton(sa,&ret); printf("inet_aton:0x%x \n",ret.s_addr); }运行结果:
[localhost 400]$ ./addr inet_addr:0xb2d26ca inet_network:0xca262d0b inet_ntoa:202.30.45.11 inet_aton:0xb2d26ca [localhost 400]$