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的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #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++的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #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的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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的代码量只有前两者的一半,要清爽得多
运行实例
三个例子所实现的交互都是一模一样的,运行截个例子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库