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

運行實例

三個例子所實現的交互都是一模一樣的,運行截個例子

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM