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的代码量只有前两者的一半,要清爽得多 

运行实例

三个例子所实现的交互都是一模一样的,运行截个例子

 

posted on   小宇2  阅读(14532)  评论(10编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库

导航

< 2012年12月 >
25 26 27 28 29 30 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 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示