2016-02-10 37 views
-4

如何將用字符串表示的IP地址打包到unsigned long中。請以更有效的方式(並使用更少的代碼)在C++中提供解決方案。 在此先感謝!如何將表示爲字符串的IP地址打包爲無符號長整數

#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

這是您編寫的代碼的正確輸出。你想要什麼結果? –

+3

除非你需要額外的東西,否則不要使用'std :: endl'。 ''\ n''開始一個新行。 –

+0

確實得到10! ?處理「。」作爲多個操作? –

回答

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類型。

+0

根據需要,用於存儲上述類型的字符串的變量類型被稱爲硬件頭文件中的slong 。所以iam試圖手動打包硬件發送的結構並執行應用程序。所以這裏需要的是如何使用slong發送上面的點分離值?謝謝請隨時要求更多的澄清 – Ragav

+0

例如:「167840383」代表「10.1.10.127」 – Ragav

+0

@Ragav:這是一個完全不同的轉換!描述確切的規則'string' - >'slong',因爲在你的例子中如何破譯算法並不明顯。 – iksemyonov

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和​​

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的特殊實現。例如印度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; 
    } 
} 
+0

謝謝我如何將上述字符串存儲到slong? – Ragav

+0

@Ragav:現在你不明白你不能嗎? –

+0

獻愛心的原因是什麼?男人問結果評論「我需要整個字符串」。 aswer正是。這是不可能的原因。這樣的答案就是問題。 – oklas

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; 
} 
+0

謝謝!任何最小化的C++版本代碼.. – Ragav

+0

「任何最小化的代碼」你是什麼意思?上述所有代碼都需要執行該操作。例如,您可以將它分成一個函數。 – iksemyonov

+0

好的..在C++中,我們可以使用一些STL,我們可以實現類似的目標嗎?只是好奇地想知道... – Ragav

相關問題