一、数据存储顺序:大端和小端
大端模式: 地址的增长顺序与值的增长顺序相反
小段模式: 地址的增长顺序与值的增长顺序相同
我们常用的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; }
说明:
1 在c中,联合体(共用体)的数据成员都是从低地址开始存放。
2 若是小端模式,由低地址到高地址c.a存放为0x01 00 00 00,c.b被赋值为0x01;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 01 00 00 00
c.b 01 00
————————————————————————————
3 若是大端模式,由低地址到高地址c.a存放为0x00 00 00 01,c.b被赋值为0x0;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 00 00 00 01
c.b 00 00
————————————————————————————
字节序的处理
因为存在大端小端的问题,所以就要进行统一的转换。
注意字符串是不用转换的,因为一个字符正好占一字节。存储顺序不影响值。而浮点数也不用转换,因为浮点数的读取规则是在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]$