ip地址和int类型的相互转换
这是我最近看到的一个面试题,还比较常见,于是用c, c++和python分别实现了 ip2int 和 int2ip, 因为我把main函数都写上了,代码显得有点杂乱,看的时候请重点看函数实现,忽略main函数
ipv4的地址本来就是用32位来表示的,分成4个8位来书写, 所以ipv4和地址是可以和32位unsigned int一一对应的,转换的算法就很显然了,把32位的整型4个字节的数分别计算出来; 反之则是ip地址4个节的数乘上对应的权值(256^3, 256^2, 256^1, 256^0)加起来即可
C的
#include<string.h> #include<stdio.h> #include<stdlib.h> #include<math.h> unsigned int ip2int(char * ipStr); const char* int2ip(unsigned int ipInt); const int IP_STR_LEN= 15; const int TOKEN_LEN = 4; int main(){ printf("1)ip2int 2)int2ip\nothers, quit\n"); int choice = 0; scanf("%d", &choice); while(choice ==1 || choice ==2){ char * pipStr = malloc(IP_STR_LEN); if(choice == 1){ printf("ipStr : "); scanf("%s", pipStr); int ipInt = ip2int(pipStr); printf("ipInt : %d\n", ipInt); }else{ printf("ipInt : "); int ipInt = 0; scanf("%d", &ipInt); pipStr = int2ip(ipInt); printf("ipStr : %s\n", pipStr); } printf("--------------\n1)ip2int 2)int2ip\nothers, quit\n"); choice = 0; //choice must be set to 0 , or unexpected thing happend scanf("%d", &choice); } printf("quit\n"); } unsigned int ip2int(char* ipStr){ unsigned int ipInt = 0; int tokenInt = 0; char * token; token = strtok(ipStr, "."); int i = 3; while(token != NULL){ // tokenInt = strtol(token, NULL, 10); //strtol comes from stdlib.h tokenInt = atoi(token); ipInt += tokenInt * pow(256, i); token = strtok(NULL, "."); i--; } return ipInt; } const char* int2ip(unsigned int ipInt){ int tokenInt = 0; unsigned int leftValue = ipInt; char * ipStr = malloc(IP_STR_LEN); char * ipToken = malloc(TOKEN_LEN); for(int i=0; i<4; i++){ int temp = pow(256, 3-i); tokenInt = leftValue / temp; leftValue %= temp; // itoa(tokenInt, ipToken, 10); //non-standard function snprintf(ipToken, TOKEN_LEN, "%d", tokenInt); if(i != 3){ strcat(ipToken, "."); } strncat(ipStr, ipToken, strlen(ipToken)); } return ipStr;
1. c编译的时候比较特别,要如下才能编译成功
gcc -std=c99 ip2int.c -lm -o ip2int
若把 ip2int.c放到最后是不能编过的,会提示pow()无法链接. -lm是链接上<math.h>这个头文件中声明的函数的库
2. c中的幂需要调用<math.h>中的pow()函数才行.
3. <stdlib.h>中有提供atoi以及一系列的strtol标准函数来实现从string到int(atoi)或是long(strtol)的转换, 但是itoa并不是<stdlib.h>中的标准函数 ,即不是c library的标准函数, 从整型到string标准的方案是使用snprintf或sprintf
4.在c中实现string的split使用的是<string.h>中的strtok函数, 上面ip2int中对strtok的使用是一个典型的例子.
C++的
#include<iostream> #include<string> #include<vector> #include<sstream> #include<cmath> #include<boost/algorithm/string.hpp> using namespace std; using namespace boost; unsigned int ip2int(string& ip); string int2ip(unsigned int ipInt); int main(){ cout << "1)ip2int 2)int2ip\nothers,quit\n"; char choice = 0; cin >> choice; while (string("12").find(choice) != string::npos){ if (choice == '1'){ cout << "ipStr : "; string ip; cin >> ip; unsigned int ipInt = ip2int(ip); cout << "ipInt : " << ipInt << "\n"; } else if (choice == '2'){ cout << "ipInt : "; unsigned int ipInt = 0; cin >> ipInt; string ip = int2ip(ipInt); cout << "ipStr : " << ip << endl; } cout << "-------------\n1)ip2int 2)int2ip\nothers,quit\n"; cin >> choice; } cout << "quit"; } unsigned int ip2int(string& ip){ vector<string> ipSecs; split(ipSecs, ip, is_any_of(".")); vector<string>::iterator it = ipSecs.begin(); unsigned int ipInt = 0; int i = 3; stringstream ss; for (; it!=ipSecs.end(); it++){ int ipSecInt = 0; ss << *it; ss >> ipSecInt; //must ss.clear() ss.clear(); ipInt += ipSecInt * pow(256,i); i--; } return ipInt; } string int2ip(unsigned int ipInt){ string ip; string ipSec; stringstream ss; int leftValue = ipInt; for(int i=3; i>=0; i--){ int temp = pow(256,i); int sectionValue = leftValue / temp; leftValue %= temp; ss << sectionValue; ss >> ipSec; ss.clear(); if(i!=0){ ipSec.append("."); } ip.append(ipSec); ipSec.clear(); } return ip; }
1.在C++中,string到整型的互转使用的是io库中的stringstream, 这也是C++标准库的解决方案, 当然boost库中也有解决方案,但我倾向于使用这个.
2.上面两个函数实现中对于stringstream的使用,当我调整了流的方向后,必须调用ss.clear(), 才能继续正常使用ss.还没有去研究这是为什么
3.对于string的split, 我使用了boost库中的东西,这个在这篇随笔中有提及.C++的标准库并没有对string的split提供直接的解决方案
Python的
import string def ip2int(ipStr): ipInt = 0 i = 3 ipTokens = str(ipStr).split('.') for ipToken in ipTokens: ipInt += int(ipToken) * (256 ** i) # or pow(256, i) i -= 1 return ipInt def int2ip(ipInt): ipStr = '' leftValue = ipInt for i in [3, 2, 1, 0]: ipTokenInt = leftValue / 256**i ipStr = ipStr + str(ipTokenInt) if i!=0: ipStr = ipStr + '.' leftValue %= 256**i return ipStr if __name__ == "__main__": choice = raw_input('1)ip2int 2)int2ip\nothers, quit\nyour choice : ') while choice in ['1', '2']: if choice == '1': ipStr = raw_input('ipStr :') ipInt = ip2int(ipStr) print 'ipInt : ', ipInt elif choice == '2': ipInt = input('ipInt : ') ipStr = int2ip(ipInt) print 'ipStr : ', ipStr choice = raw_input('-------------------\n1)ip2int 2)int2ip\nothers, quit\nyour choice : ') print 'quit'
1. Python中的幂既可以用**也可以用pow(), 如第8行.
2. input用到了两种, input和raw_input, raw_input就是输入的的字符串, 而input其实是用raw_input实现的,它会处理输入的东西,若是数字,则转换为相应的类型
3. string的分隔用的是string.split,实际上这个方法已经被废弃了,但还是会在python3中支持,但新的方法怎么使用我没看明白, string concatination用的是 + . 可以看到6,7行string的split和遍历是多么简洁的代码就搞定了
其实上面三个实现用到的实现算法都是一模一样的, 可以很明显的看到,Python的代码量只有前两者的一半,要清爽得多
运行实例
三个例子所实现的交互都是一模一样的,运行截个例子