Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从字符串获取IPv4地址的最快方法_C++_C_String_Optimization_Ip Address - Fatal编程技术网

C++ 从字符串获取IPv4地址的最快方法

C++ 从字符串获取IPv4地址的最快方法,c++,c,string,optimization,ip-address,C++,C,String,Optimization,Ip Address,我有以下代码,大约比inet_addr快7倍。我想知道是否有一种方法可以改进它,使它更快,或者是否有一种更快的替代方法 这段代码要求提供一个有效的以null结尾的IPv4地址,并且不带空格,在我的例子中总是这样,所以我针对这种情况进行了优化。通常,您会有更多的错误检查,但是如果有一种方法可以使下面的操作更快,或者有一种更快的替代方法,我将非常感激 UINT32 GetIP(const char *p) { UINT32 dwIP=0,dwIP_Part=0; while(true

我有以下代码,大约比inet_addr快7倍。我想知道是否有一种方法可以改进它,使它更快,或者是否有一种更快的替代方法

这段代码要求提供一个有效的以null结尾的IPv4地址,并且不带空格,在我的例子中总是这样,所以我针对这种情况进行了优化。通常,您会有更多的错误检查,但是如果有一种方法可以使下面的操作更快,或者有一种更快的替代方法,我将非常感激

UINT32 GetIP(const char *p)
{
    UINT32 dwIP=0,dwIP_Part=0;
    while(true)
    {
        if(p[0] == 0)
        {
            dwIP = (dwIP << 8) | dwIP_Part;
            break;
        }
        if(p[0]=='.') 
        {       
            dwIP = (dwIP << 8) | dwIP_Part;                     
            dwIP_Part = 0;
           p++;
        }
        dwIP_Part = (dwIP_Part*10)+(p[0]-'0');
        p++;
    }
    return dwIP;
}
UINT32 GetIP(const char*p)
{
UINT32 dwIP=0,dwIP_部分=0;
while(true)
{
if(p[0]==0)
{

dwIP=(dwIP因为我们谈论的是最大化IP地址解析的吞吐量,所以我建议使用向量化解决方案

以下是x86特定的fast解决方案(需要SSE4.1,对于穷人,至少需要SSSE3):

\uuum128i shuffleTable[65536];//可以减少256倍,请参阅@iwillnotexistidnotexist
UINT32 MyGetIP(常量字符*str){
__m128i输入=_mm_lddqu_si128((常量m128i*)str);/“192.167.1.3”
输入=_mm_sub_epi8(输入,_mm_set1_epi8('0'));/1 9 2 254 1 6 7 254 1 254 3 208 245 0 8 40
__m128i cmp=输入;/…X…X.X.XX…(符号)
UINT32掩码=_mm_movemask_epi8(cmp);//6792-魔法索引
__m128i shuf=shuffleTable[mask];//10-1-1-18-1-1-1654-1120-1
__m128i arr=_mm_shuffle_epi8(输入,shuf);/3 0 0 0 0 0 0 0 0 0 0 7 6 1 0 0 2 9 1 0
__m128i系数=_mm_set_epi8(0,100,10,1,0,100,10,1,0,100,10,1,0,100,10,1,100,10,1);
__m128i prod=_mm_maddubs_epi16(系数,arr);/3 0 | 1 0 | 67 100 | 92 100
prod=_mm_hadd_epi16(prod,prod);/3 | 1 | 167 | 192 |?|?|?|?
__m128i imm=_mm_set_epi8(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,6,4,2,0);
prod=_mm_shuffle_epi8(prod,imm);//31167192 0 0 0 0 0 0 0
返回_mm_extract_epi32(prod,0);

//返回(UINT32(_-mm_-extract_-epi16(prod,1))作为备选方案:这与您的类似,但有一些错误检查:

#include <iostream>
#include <string>
#include <cstdint>

uint32_t getip(const std::string &sip)
{
    uint32_t r=0, b, p=0, c=0;
    const char *s;
    s = sip.c_str();
    while (*s)
    {
        r<<=8;
        b=0;
        while (*s&&((*s==' ')||(*s=='\t'))) s++;
        while (*s)
        {
            if ((*s==' ')||(*s=='\t')) { while (*s&&((*s==' ')||(*s=='\t'))) s++; if (*s!='.') break; }
            if (*s=='.') { p++; s++; break; }
            if ((*s>='0')&&(*s<='9'))
            {
                b*=10;
                b+=(*s-'0');
                s++;
            }
        }
        if ((b>255)||(*s=='.')) return 0;
        r+=b;
        c++;
    }
    return ((c==4)&&(p==3))?r:0;
}

void testip(const std::string &sip)
{
    uint32_t nIP=0;
    nIP = getip(sip);
    std::cout << "\nsIP = " << sip << " --> " << std::hex << nIP << "\n";
}

int main()
{
    testip("192.167.1.3");
    testip("292.167.1.3");
    testip("192.267.1.3");
    testip("192.167.1000.3");
    testip("192.167.1.300");
    testip("192.167.1.");
    testip("192.167.1");
    testip("192.167..1");
    testip("192.167.1.3.");
    testip("192.1 67.1.3.");
    testip("192 . 167 . 1 . 3");
    testip(" 192 . 167 . 1 . 3 ");
    return 0;
}
#包括
#包括
#包括
uint32_t getip(常量标准::字符串和sip)
{
uint32_t r=0,b,p=0,c=0;
常量字符*s;
s=sip.c_str();
而(*s)
{

我认为这更适合codereview.stackexchange.comWhy?我想知道从字符串中获取IP地址的最快方法是什么。您还应该注意,如果不将Endianness调整为网络字节顺序,UINT32可能不适合IP地址。@Harry codereview专门检查工作代码(您的代码工作正常),他们可以提出算法改进建议。这并不是说速度黑客不在这里讨论的主题。@Iwillnotexist Idonotexist我想如果我的代码确实是目前世界上最快的,那么可能值得去codereview看看它是否能更快?;)我在这里看到过更快的整数转换问题,我认为这与这些类型的问题有关。我自己在这个主题上找不到任何其他问题,如果没有其他选择,它可能会在将来帮助其他人。@PeterCordes
pmovskb
指令保证零填充整个寄存器(
r32
r64
)它被要求爆炸。不幸的是,
\u mm\u movemask\u epi8()
和底层(在GCC上)
\u内置的ia32\u pmovskb128()
intrinsic都返回
int
,因此编译器迫切希望使用
pmovmkb r32,xmm
表单,而不是本应获利的
pmovmkb r64,xmm
表单。然后,编译器感觉需要对extend进行签名,因为返回值名义上是
int
。我也注意到了这一点,并尝试了to抑制它,但意识到问题是根深蒂固的。@Harry您必须绝对使该表消失,或者您是否能够使其更小(例如,256个条目x 16个字节/条目?)如果是这样的话,可以修改stgatilov的代码,用一个完美的散列提取81个可能的有效数字掩码。我散列的一个秘密技巧是使用单个SSE4.2指令CRC,可以与
\u mm\u crc32.*()
一起使用。对于这个用例,在
掩码=\u mm\u crc32\u u16(0,mask>(32-n)中找到
a
n
这样您就有了
2^n
个容器,并且在散列之后没有任何有效的掩码发生冲突。您可能应该能够得到n=8(256个条目)。@EvgenyKluev I成功地制作了一个256个容器的完美散列变体,它是stgatilov的优秀开端。(警告,使用了与GCC一致的属性)。它的速度只有原来的一半多,但LUT占用的空间却少了256倍。先生们,我刚刚通过在完美哈希中使用不同的魔法乘法常数成功地删除了
crc
指令。因此,它甚至不需要SSE4.2,而且速度稍快。目前,在我的i7-4700MQ处理器上,时间资源:stgatilov@
0.465
,我自己
0.645
和哈里
2.996
秒。空间资源:stgatilov@1MB,我自己@4KB,哈里@wherry@微不足道。因此,我的速度慢了40%,但占用了0.4%的内存,我的哈希表负载因子是81/256~31.6%,而不是81/65536~0.12%。@哈里:我没有测试它,但我预计如果我们完成的话用计算代替查找,这将使最快的算法速度降低2到3倍。但它可能比您的版本快得多,因为许多计算是并行完成的。Skylake体系结构即将推出,它允许对
lzcnt
指令进行矢量化(使用AVX512指令集)因此,几乎所有的计算都可以并行进行;但它不太可能比这里提到的两种方法都好。与我最初的方法相比,你的速度是多少?@Harry:我没有做(没有数据)特定的批量速度测试;反正只与特定的批量速度相关
lddqu   xmm1, XMMWORD PTR [rcx]
psubb   xmm1, xmm6
pmovmskb ecx, xmm1
mov ecx, ecx               //useless, see @PeterCordes and @IwillnotexistIdonotexist
add rcx, rcx               //can be removed, see @EvgenyKluev
pshufb  xmm1, XMMWORD PTR [r13+rcx*8]
movdqa  xmm0, xmm8
pmaddubsw xmm0, xmm1
phaddw  xmm0, xmm0
pshufb  xmm0, xmm7
pextrd  eax, xmm0, 0
#include <iostream>
#include <string>
#include <cstdint>

uint32_t getip(const std::string &sip)
{
    uint32_t r=0, b, p=0, c=0;
    const char *s;
    s = sip.c_str();
    while (*s)
    {
        r<<=8;
        b=0;
        while (*s&&((*s==' ')||(*s=='\t'))) s++;
        while (*s)
        {
            if ((*s==' ')||(*s=='\t')) { while (*s&&((*s==' ')||(*s=='\t'))) s++; if (*s!='.') break; }
            if (*s=='.') { p++; s++; break; }
            if ((*s>='0')&&(*s<='9'))
            {
                b*=10;
                b+=(*s-'0');
                s++;
            }
        }
        if ((b>255)||(*s=='.')) return 0;
        r+=b;
        c++;
    }
    return ((c==4)&&(p==3))?r:0;
}

void testip(const std::string &sip)
{
    uint32_t nIP=0;
    nIP = getip(sip);
    std::cout << "\nsIP = " << sip << " --> " << std::hex << nIP << "\n";
}

int main()
{
    testip("192.167.1.3");
    testip("292.167.1.3");
    testip("192.267.1.3");
    testip("192.167.1000.3");
    testip("192.167.1.300");
    testip("192.167.1.");
    testip("192.167.1");
    testip("192.167..1");
    testip("192.167.1.3.");
    testip("192.1 67.1.3.");
    testip("192 . 167 . 1 . 3");
    testip(" 192 . 167 . 1 . 3 ");
    return 0;
}