我需要(或多或少)实时处理大量这些。我正在使用的方法不再削减它了。
std::string parse_ipv4_address( const std::vector<unsigned char> & data, int start )
{
char ip_addr[16];
snprintf( ip_addr, sizeof(ip_addr), "%d.%d.%d.%d",
data[start + 0], data[start + 1], data[start + 2], data[start + 3] );
return std::string( ip_addr );
}
// used like this
std::vector<unsigned char> ip = { 0xc0, 0xa8, 0x20, 0x0c };
std::string ip_address = parse_ipv4_address( ip, 0 );
std::cout << ip_address << std::endl; // not actually printed in real code
// produces 192.168.32.12
有更快的方法吗?怎么样?
请注意!性能是这里的问题,因此this issue不是重复的。
答案 0 :(得分:5)
以下是影响绩效的潜在候选人:
snprintf
需要解析格式字符串,并执行错误处理。要么花费时间,要么实现你不需要的功能。std::string
对象的代价很高。它将受控序列存储在freestore内存中(通常实现为堆内存),这在C ++(和C)中分配成本有点高。std::vector
存储4字节值会不必要地占用资源。它也在freestore中分配内存。将其替换为char[4]
或32位整数(uint32_t
)。由于您不需要printf
- 函数族的多功能性,您可以完全放弃它,并使用查找表。查找表由256个条目组成,每个条目保存字节值0到255的可视化表示。为了优化它,让LUT包含尾随的.
字符。 (需要特别注意,以解决字节序。我在这里假设小端。)
解决方案可能看起来像 1):
const uint32_t mapping[] = { 0x2E303030, // "000."
0x2E313030, // "001."
// ...
0x2E343532, // "254."
0x2E353532 // "255."
};
alignas(uint32_t) char ip_addr[16];
uint32_t* p = reinterpret_cast<uint32_t*>(&ip_addr[0]);
p[0] = mapping[data[0]];
p[1] = mapping[data[1]];
p[2] = mapping[data[2]];
p[3] = mapping[data[3]];
// Zero-terminate string (overwriting the superfluous trailing .-character)
ip_addr[15] = '\0';
// As a final step, waste all the hard earned savings by constructing a std::string.
// (as an ironic twist, let's pick the c'tor with the best performance)
return std::string(&ip_addr[0], &ip_addr[15]);
// A more serious approach would either return the array (ip_addr), or have the caller
// pass in a pre-allocated array for output.
return ip_addr;
<小时/> 1) 免责声明:从
char*
转换为uint32_t*
技术上展示未定义的行为。 请勿使用,除非您的平台(编译器和操作系统)提供额外的保证,以便明确定义。
答案 1 :(得分:2)
三个 四个答案,价格为一个。
首先,确实,确定你正在优化正确的部分。 std::vector
和std::string
创建都涉及内存分配,cout <<
可能涉及文件访问,图形等!
第二:不要使用向量来表示IP地址的4字节。只需使用char ip[4]
,甚至是32位整数
第三:我猜你没有处理完全随机的IP地址。可能是几百或几千个不同的地址?在这种情况下,使用std::map<INT32, std::string>
作为缓存,只需根据需要从缓存中提取所需的缓存,然后根据需要编写新的缓存。如果缓存太大,只需将其清空并重新开始......
<小时/> 第四:考虑用十六进制虚线四边形表示法编写IP地址。像
inet_addr()
之类的调用仍然可以接受这一点,它有几个优点:所有字段都是固定宽度,只有8个'字符'可以更新,二进制到十六进制转换通常比二进制到十进制更快。 https://en.wikipedia.org/wiki/IPv4#Address_representations
答案 2 :(得分:0)
您可以使用查找表,其中包含0到255之间的数字字符串。 如果速度非常重要,您还可以使用内联关键字或函数宏。 你也可以查看sse说明。
顺便说一下,通常代码越原始越快。我会使用unsigned char数组而不是vector,char数组而不是字符串,memcpy(甚至直接逐字节复制)而不是sprintf。
答案 3 :(得分:0)
您在这里...
std::string IP_parse(unsigned char data[4])
{
std::string parsedString = "";
snprintf((char*)parsedString.c_str(), sizeof(char[15]), "%d.%d.%d.%d", data[0], data[1], data[2], data[3]);
return parsedString;
}