一、数据存储顺序:大端和小端
大端模式: 地址的增长顺序与值的增长顺序相反
小段模式: 地址的增长顺序与值的增长顺序同样
为什么会有大小端模式之分呢?这是由于在计算机系统中,我们是以字节为单位的。每一个地址单元都相应着一个字节。一个字节为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! "); else printf("It is Big_endian! "); return 1; }说明:
1 若是小端模式,由低地址到高地址c.a存放为0x01 00 00 00。c.b被赋值为0x01;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 01 00 00 00
c.b 01
————————————————————————————
2 若是大端模式,由低地址到高地址c.a存放为0x00 00 00 01,c.b被赋值为0x0;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 00 00 00 01
c.b 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 ",at); //将点分十进制字符串转换为32位主机字节序。与网络字节序应该是反过来的 printf("inet_network:0x%x ",inet_network(sa)); //结构体中记录IP地址的数据成员 addr.s_addr=at; //网络字节序转换为点分十进制数 printf("inet_ntoa:%s ",inet_ntoa(addr)); //点分十进制数转换为网络字节序,參数为结构体 inet_aton(sa,&ret); printf("inet_aton:0x%x ",ret.s_addr); }执行结果:
[localhost 400]$ ./addr inet_addr:0xb2d26ca inet_network:0xca262d0b inet_ntoa:202.30.45.11 inet_aton:0xb2d26ca [localhost 400]$