如何将用字符串表示的IP地址打包到unsigned long
。请以更有效的方式使用C ++提供解决方案(并且代码更少)。
在此先感谢!!!
#include<iostream>
#include<cstring>
#include<cstdlib>
int main()
{
unsigned long Id1;
std::string item = "1.2.3.4";
Id1 = ??(here item need to be packed in Id1)
std::cout << Id1 <<std::endl;
}
答案 0 :(得分:1)
atol
看到数字,直到出现非数字
整个字符串不是数字,您将从此代码中看到整个字符串
int main()
{
long Id1;
std::string item = "1.2.3.4.5.6.7.8.9.10";
std::cout << item << std::endl;
}
<强> UPD:强>
我建议我有效和普遍的算法:
PARAMS:
str - string to parse
sep - fiels separator, which delimit digit position
textbase - radix of digits in text string
fieldbase - field radix of position in target number
在此处查看基数:https://en.wikipedia.org/wiki/Radix和https://en.wikipedia.org/wiki/Numeral_system
template<typename T>
T str2num( const std::string &str, char sep, int textbase, int fieldbase ) {
T digit, result = 0;
std::size_t pos=0, start = 0, end = str.size() - 1;
std::string strnum;
while( ( start = str.rfind(sep,end) ) != std::string::npos ) {
strnum = str.substr( start + 1, end - start );
digit = std::strtol( strnum.c_str(), 0, textbase );
result += digit * pow( fieldbase, pos );
end = start - 1;
++pos;
}
strnum = str.substr( 0, end + ( start ? 1 : 0 ) );
digit = std::strtol( strnum.c_str(), 0, textbase );
result += digit * pow( fieldbase, pos );
return result;
}
因此,此通用功能可用于任何类比目的。例如,将IP地址从字符串解析并转换为二进制形式。目前IPv4很简单。但是,当编译器支持128位宽度整数值时,IPv6将变得简单。但是当前IPv6可以用拆分字符串解析为具有四个字段的两个子字符串。
有一个例子如何使用:
int main()
{
typedef unsigned long ul32;
typedef unsigned long long ul64;
// parse the IPv4 adress, where numerical system of digits
// in fields id 10, and field radix is 256 (in hex 0x100)
ul32 x32 = str2num<ul32>( "10.1.10.127", '.', 10, 256 );
std::cout << x32 << std::endl;
// parse half of the IPv6 adress, where numerical system of digits
// in fields id 16, and field radix is 65536 (in hex 0x10000)
ul64 x64 = str2num<ul64>( "1234:5678:9abc:def0", ':', 16, 65536 );
std::cout << std::hex << x64 << std::endl;
return 0;
}
结果输出:
167840383
123456789abcdef0
PS:
当您尝试使用64位整数编译时,标准库pow()函数不支持64位值,因此需要使用pow的特殊实现。例如印度战俘算法。我在这里找到了pascal实现:http://www.algolib.narod.ru/Math/IndianPow.html所以转换为c ++:
template<typename T>
T pow( T base, unsigned int exp ) {
T t = base, res = 1;
while( 1 ) {
if ( exp & 1 ) res *= t;
exp >>= 1;
if ( ! exp ) return res;
t *= t;
}
}
答案 1 :(得分:1)
您的问题不明确,因为您的字符串包含小数点,signed long
是不可或缺的。
另外,如果我们将'.'
字符作为分隔符,这意味着字符串中有10个数字而不是一个。
如果要将字符串中的字符复制到signed long
占用的内存中,可以尝试这样的操作:
int main(void)
{
signed long value = 0;
const std::string item = "1.2.3.4.5.6.7.8.9.10";
for (unsigned int i = 0; i < sizeof(signed long); ++i)
{
// shift left one byte to make room for the next character
value = value * 256;
// Insert the character from the string.
value += string[i];
}
另一种方法是使用memcpy
:
memcpy(&value, item.c_str(), sizeof(signed long));
修改1:复制到slong
使用上面的例子,'。'字符被跳过:
int main(void)
{
slong value = 0;
const unsigned int destination_capacity = sizeof(slong);
const std::string item = "1.2.3.4.5.6.7.8.9.10";
const unsigned int length = item.size();
unsigned int chars_copied = 0U;
for (unsigned int i = 0; i < length; ++i)
{
const char c = item[i];
if (isdigit(c))
{
// shift left one byte to make room for the next character
value = value * 256;
// Insert the character from the string.
value += string[i];
chars_copied++;
if (chars_copied >= destination_capacity)
{
break;
}
}
return EXIT_SUCCESS;
}
以上复制字符串中的数字字符并将其打包成slong
类型。
答案 2 :(得分:0)
编辑:它不是剥离点,而是将4个字段打包成一个unsigned long
。以下是我对标准库的看法:
再次编辑:现在使用保险箱stoi()
,使用包装器。 (可惜我们没有类似Erlang的元组返回类型和模式匹配。)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
std::pair<bool, int> stoi_wrap(const std::string& s)
{
std::pair<bool, int> res(true, 0);
try {
res.second = std::stoi(s);
} catch (std::exception e) {
res.first = false;
}
return res;
}
int main(int agrc, char **argv)
{
std::string s = "10.1.10.127";
std::vector<unsigned char> fields;
std::stringstream stream(s); std::string temp;
while(std::getline(stream, temp, '.')) {
const auto res = stoi_wrap(temp);
if (!res.first) {
std::cerr << "error reading a field" << '\n'; return -1;
}
else
fields.push_back(res.second);
}
if (fields.size() != 4) {
std::cerr << "wrong field count" << std::endl; return -1;
}
unsigned long int result{}; int i{};
for (auto it = fields.rbegin(); it != fields.rend(); it++) {
result += *it << 8*i; ++i;
}
std::cout << result << std::endl;
}