如何将表示为字符串的IP地址打包为unsigned long

时间:2016-02-10 20:10:30

标签: c++ string c++11 type-conversion

如何将用字符串表示的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;
    }

3 个答案:

答案 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/Radixhttps://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;
}