一、数据存储顺序:大端和小端
高位字节存储高字节称为小端模式,通常都计算机采用这个模式存储。而网络则采用大端传输。所以需要转换
面试有时会出这么个题:写一个程序判断程序的存储是大端还是小端?
程序的原理见下图:
- #include<stdio.h>
- #include<stdlib.h>
- union word{
- int a;
- char b;
- }c;
- int check(){
- c.a=1;
- return (c.b == 1)? 0:1;
- }
- int main(){
- if(check()){
- printf(”big\n”);
- }else{
- printf(”Little\n”);
- }
- }
#include<stdio.h>
include<stdlib.h>
union word{
int a;
char b;
}c;
int check(){
c.a=1;
return (c.b == 1)? 0:1;
}
int main(){
if(check()){
printf("big\n");
}else{
printf("Little\n");
}
}
利用Union的特点,判断出了大端还是小端。
还有一道经典的面试题是 :
- #include<stdio.h>
- int main(){
- int a[]={1,2,3,4};
- int *ptr1 = (int *)(&a+1);
- int *ptr2 = (int *)((int)a+1);
- printf(”%x , %x\n”,ptr1[-1],*ptr2);
- }
#include<stdio.h>
int main(){
int a[]={1,2,3,4};
int *ptr1 = (int *)(&a+1);
int *ptr2 = (int *)((int)a+1);
printf("%x , %x\n",ptr1[-1],*ptr2);
}
结果是:2 , 2000000 。
第一个值的计算请参考 面试知识总结(一) 中的第四题。
第二个值的计算如下图:
将a转换为整形,然后增加1,再转回指针型,相当于只移动了一个bit。由于是小端存储,会将下一个数的末尾读进来。
二、字节序的处理。
因为存在大端小端的问题,所以就要进行统一的转换。
注意字符串是不用转换的,因为一个字符正好占一字节。存储顺序不影响值。而浮点数也不用转换,因为浮点数的读取规则是在cpu中定义的,是一致的。
转换所用的函数为:
htons(),htonl(); 主机转为网络字节序,s为short , l为long
ntohs(),ntohl(); 网络转为主机字节序。
三、地址格式的转换
通常情况下,都是用点分十进制(如:202.134.23.145)来表示IP地址。是个字符串。但是程序中处理时用到的是一个二进制的值。所以要进行转换。
对于IPV4有以下4个函数:
- #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);
- }
#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);
}
编译运行的结果:
- [fsy@localhost 400] ./addr </span></span></li><li class=""><span>inet_addr:0xb2d26ca </span></li><li class="alt"><span>inet_network:0xca262d0b </span></li><li class=""><span>inet_ntoa:202.30.45.11 </span></li><li class="alt"><span>inet_aton:0xb2d26ca </span></li><li class=""><span>[fsy@localhost 400]
- inet_addr:0xb2d26ca
- inet_network:0xca262d0b
- inet_ntoa:202.30.45.11
- inet_aton:0xb2d26ca
- [fsy@localhost 400]
[fsy@localhost 400]$ ./addr
inet_addr:0xb2d26ca
inet_network:0xca262d0b
inet_ntoa:202.30.45.11
inet_aton:0xb2d26ca
[fsy@localhost 400]$
而对于结构不同的IPV6就不行了。但有两个函数可以通用于IPV4和IPV6:
- #include<stdio.h>
- #include<stdlib.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- int main(){
- struct in_addr ret;
- //IPV6的ip结构体
- struct in6_addr ret6;
- //存储转换的IP地址
- char buf[32];
- //IPV4
- char* sa=“202.128.47.168”;
- //IPV6
- char* sa6=“fe80::20c:29ff:fe5f:8760”;
- //点分十进制转为网络字节序,第一个参数表示IPV4
- inet_pton(AF_INET,sa,&ret);
- printf(”pton: 0x%x\n”,ret.s_addr);
- //网络字节序转为点分十进制,第二个参数为要转换的值,第三个参数为转换后存储的位置,第四个参数为字符串的最大长度
- inet_ntop(AF_INET,&ret,buf,32);
- printf(”ntop: %s\n”,buf);
- //IPV6的用法一样只是第一个参数改为AF_INET6
- inet_pton(AF_INET6,sa6,&ret6);
- printf(”pton: 0x%x\n”,ret6.s6_addr);
- inet_ntop(AF_INET6,&ret6,buf,32);
- printf(”ntop: %s\n”,buf);
- }
#include<stdio.h>
include<stdlib.h>
include<netinet/in.h>
include<arpa/inet.h>
int main(){
struct in_addr ret;
//IPV6的ip结构体
struct in6_addr ret6;
//存储转换的IP地址
char buf[32];
//IPV4
char* sa="202.128.47.168";
//IPV6
char* sa6="fe80::20c:29ff:fe5f:8760";
//点分十进制转为网络字节序,第一个参数表示IPV4
inet_pton(AF_INET,sa,&ret);
printf("pton: 0x%x\n",ret.s_addr);
//网络字节序转为点分十进制,第二个参数为要转换的值,第三个参数为转换后存储的位置,第四个参数为字符串的最大长度
inet_ntop(AF_INET,&ret,buf,32);
printf("ntop: %s\n",buf);
//IPV6的用法一样只是第一个参数改为AF_INET6
inet_pton(AF_INET6,sa6,&ret6);
printf("pton: 0x%x\n",ret6.s6_addr);
inet_ntop(AF_INET6,&ret6,buf,32);
printf("ntop: %s\n",buf);
}
四、域名与IP信息的解析
IP地址不好记,所以便有了域名。
可以通过返回主机信息:
- #include<stdio.h>
- #include<stdlib.h>
- #include<netinet/in.h>
- #include<netdb.h>
- int main(int argc,char **argv){
- char *ptr,**pptr;
- struct hostent *hptr;
- char addr[32];
- if(argc>1){
- //将信息存入结构体中
- if((hptr=gethostbyname(argv[1]))== NULL){
- printf(”gethostbyname error!:%s\n”,argv[1]);
- exit(1);
- }
- //输出主机名
- printf(”h_name: %s\n”,hptr->h_name);
- //主机备选名称,以NULL结尾的列表
- for(pptr=hptr->h_aliases;*pptr!=NULL;pptr++){
- printf(”alias: %s\n”,*pptr);
- }
- //主机网络地址,以NULL结尾的列表
- for(pptr=hptr->h_addr_list;*pptr!=NULL;pptr++){
- inet_ntop(hptr->h_addrtype,*pptr,addr,sizeof(addr));
- printf(”addr :%s \n”,addr);
- }
- }
- }
#include<stdio.h>
include<stdlib.h>
include<netinet/in.h>
include<netdb.h>
int main(int argc,char **argv){
char *ptr,**pptr;
struct hostent *hptr;
char addr[32];
if(argc>1){
//将信息存入结构体中
if((hptr=gethostbyname(argv[1]))== NULL){
printf("gethostbyname error!:%s\n",argv[1]);
exit(1);
}
//输出主机名
printf("h_name: %s\n",hptr->h_name);
//主机备选名称,以NULL结尾的列表
for(pptr=hptr->h_aliases;*pptr!=NULL;pptr++){
printf("alias: %s\n",*pptr);
}
//主机网络地址,以NULL结尾的列表
for(pptr=hptr->h_addr_list;*pptr!=NULL;pptr++){
inet_ntop(hptr->h_addrtype,*pptr,addr,sizeof(addr));
printf("addr :%s \n",addr);
}
}
}编译输出为:
- [fsy@localhost 400] ./gethost www.baidu.com </span></span></li><li class=""><span>h_name: www.a.shifen.com </span></li><li class="alt"><span>alias: www.baidu.com </span></li><li class=""><span>addr :119.75.217.56 </span></li><li class="alt"><span>addr :119.75.218.45 </span></li><li class=""><span>[fsy@localhost 400]<script id="MathJax-Element-5" type="math/tex"> ./gethost www.baidu.com </span></span></li><li class=""><span>h_name: www.a.shifen.com </span></li><li class="alt"><span>alias: www.baidu.com </span></li><li class=""><span>addr :119.75.217.56 </span></li><li class="alt"><span>addr :119.75.218.45 </span></li><li class=""><span>[fsy@localhost 400]</script>
[fsy@localhost 400]$ ./gethost www.baidu.com
h_name: www.a.shifen.com
alias: www.baidu.com
addr :119.75.217.56
addr :119.75.218.45
[fsy@localhost 400]$
本篇博客出自 阿修罗道,转载出处:http://blog.csdn.net/fansongy/article/details/6894960