我在std :: string中保存了十六进制MAC地址。将该MAC地址转换为uint64_t中保存的整数类型的最佳方法是什么?
我知道stringstream,sprintf,atoi等。我实际上用前两个编写了很少的转换函数,但它们似乎比我想要的更加草率。
所以,有人能告诉我一个好的,干净的转换方式
std::string mac = "00:00:12:24:36:4f";
进入uint64_t?
PS:我没有可用的boost / TR1设施,也无法在实际使用代码的地方安装它们(这也是为什么我没有复制粘贴我的尝试之一,抱歉!)。所以请保留直接C / C ++调用的解决方案。如果您有一个有趣的UNIX系统调用解决方案,我也会感兴趣!
答案 0 :(得分:8)
uint64_t string_to_mac(std::string const& s) {
unsigned char a[6];
int last = -1;
int rc = sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n",
a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
&last);
if(rc != 6 || s.size() != last)
throw std::runtime_error("invalid mac address format " + s);
return
uint64_t(a[0]) << 40 |
uint64_t(a[1]) << 32 |
uint64_t(a[2]) << 24 |
uint64_t(a[3]) << 16 |
uint64_t(a[4]) << 8 |
uint64_t(a[5]);
}
答案 1 :(得分:4)
我的解决方案(需要c ++ 11):
#include <string>
#include <cstdint>
#include <algorithm>
#include <stdlib.h>
uint64_t convert_mac(std::string mac) {
// Remove colons
mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
// Convert to uint64_t
return strtoul(mac.c_str(), NULL, 16);
}
答案 2 :(得分:3)
使用sscanf:
std::string mac = "00:00:12:24:36:4f";
unsigned u[6];
int c=sscanf(mac.c_str(),"%x:%x:%x:%x:%x:%x",u,u+1,u+2,u+3,u+4,u+5);
if (c!=6) raise_error("input format error");
uint64_t r=0;
for (int i=0;i<6;i++) r=(r<<8)+u[i];
// or: for (int i=0;i<6;i++) r=(r<<8)+u[5-i];
答案 3 :(得分:1)
我想不出任何魔术。这是一个随机尝试,可能会或可能不会比你做的更好。这简洁,但我敢打赌,解决方案要快得多。
uint64_t mac2int(std::string s) {
uint64_t r=0;
std::string::iterator i;
std::string::iterator end = s.end();
for(i = s.begin; i != end; ++i) {
char let = *i;
if (let >= '0' && let <= '9') {
r = r*0xf + (let-'0');
} else if (let >= 'a' && let <= 'f') {
r = r*0xf + (let-'a'+10);
} else if (let >= 'A' && let <= 'F') {
r = r*0xf + (let-'A'+10);
}
}
return r;
}
答案 4 :(得分:1)
我的2美分:
uint64_t ParseMac(const std::string& str)
{
std::istringstream iss(str);
uint64_t nibble;
uint64_t result(0);
iss >> std::hex;
while(iss >> nibble) {
result = (result << 8) + nibble;
iss.get();
}
return result;
}
答案 5 :(得分:1)
这只会移动十六进制数字直到字符串用完,而不是关心分隔符或总长度。但它将输入字符串转换为所需的uint64_t格式。
#include <string>
#include <stdint.h>
uint64_t cvt(std::string &v)
{
std::string::iterator i;
std::string digits = "0123456789abcdefABCDEF";
uint64_t result = 0;
size_t pos = 0;
i = v.begin();
while (i != v.end())
{
// search for character in hex digits set
pos = digits.find(*i);
// if found in valid hex digits
if (pos != std::string::npos)
{
// handle upper/lower case hex digit
if (pos > 0xf)
{
pos -= 6;
}
// shift a nibble in
result <<= 4;
result |= pos;
}
++i;
}
return result;
}
答案 6 :(得分:1)
另一个没有调用库函数的更快版本:
inline unsigned read_hex_byte(char const** beg, char const* end) {
if(end - *beg < 2)
throw std::invalid_argument("");
unsigned hi = (*beg)[0], lo = (*beg)[1];
*beg += 2;
hi -= hi >= '0' && hi <= '9' ? '0' :
hi >= 'a' && hi <= 'f' ? 'a' - 10 :
hi >= 'A' && hi <= 'F' ? 'A' - 10 :
throw std::invalid_argument("");
lo -= lo >= '0' && lo <= '9' ? '0' :
lo >= 'a' && lo <= 'f' ? 'a' - 10 :
lo >= 'A' && lo <= 'F' ? 'A' - 10 :
throw std::invalid_argument("");
return hi << 4 | lo;
}
uint64_t string_to_mac2(std::string const& s) {
char const *beg = s.data(), *end = beg + s.size();
uint64_t r;
try {
r = read_hex_byte(&beg, end);
beg += beg != end && ':' == *beg;
r = r << 8 | read_hex_byte(&beg, end);
beg += beg != end && ':' == *beg;
r = r << 8 | read_hex_byte(&beg, end);
beg += beg != end && ':' == *beg;
r = r << 8 | read_hex_byte(&beg, end);
beg += beg != end && ':' == *beg;
r = r << 8 | read_hex_byte(&beg, end);
beg += beg != end && ':' == *beg;
r = r << 8 | read_hex_byte(&beg, end);
} catch(std::invalid_argument&) {
beg = end - 1;
}
if(beg != end)
throw std::runtime_error("invalid mac address format " + s);
return r;
}
答案 7 :(得分:1)
更多没有输入数据验证的C ++ 11方式:
uint64_t stomac( const std::string &mac )
{
static const std::regex r{ "([\\da-fA-F]{2})(:|$)" };
auto it = std::sregex_iterator( mac.begin(), mac.end(), r );
static const auto end = std::sregex_iterator();
return std::accumulate( it, end, 0, []( uint64_t i, const std::sregex_iterator::value_type &v ) {
return ( i << 8 ) + std::stol( v.str(1), nullptr, 16 );
} );
}
答案 8 :(得分:1)
您还可以使用ASCII到struct ether_addr
的转换例程ether_aton
或其线程安全版本ether_aton_r
(GNU扩展)。
#include <netinet/ether.h>
#include <stdint.h>
#include <string>
#define ETHER_ADDR_ERR UINT64_C(~0)
uint64_t ether_atou64( const std::string& addr_str ) {
union {
uint64_t result;
struct ether_addr address;
};
result = 0;
struct ether_addr* ptr = ether_aton_r( addr_str.c_str(), &address );
if( !ptr ) {
return ETHER_ADDR_ERR;
}
return result;
}