Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.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 strlen性能实现_C_String_Performance_Strlen - Fatal编程技术网

C strlen性能实现

C strlen性能实现,c,string,performance,strlen,C,String,Performance,Strlen,这是一个多用途的问题: 这与实现相比如何 总的来说,有没有更好的方法来实现这一点和自动矢量化 #包括 #包括 #包括 #包括 #包括 #包括 /*待办事项:文件*/ #定义单词低((大小)-1/UCHAR\u最大值) #定义WORD_one_HIGH(((size_t)-1/UCHAR_MAX)这个实现基于几乎相同的技巧()正如您链接的glibc实现一样。它们做的事情几乎相同,只是在glibc版本中,一些循环被展开,位掩码被显式地拼写出来。您发布的代码中的个和个高完全是glibc版本中的hi

这是一个多用途的问题:

  • 这与实现相比如何
  • 总的来说,有没有更好的方法来实现这一点和自动矢量化
#包括
#包括
#包括
#包括
#包括
#包括
/*待办事项:文件*/
#定义单词低((大小)-1/UCHAR\u最大值)

#定义WORD_one_HIGH(((size_t)-1/UCHAR_MAX)这个实现基于几乎相同的技巧()正如您链接的glibc实现一样。它们做的事情几乎相同,只是在glibc版本中,一些循环被展开,位掩码被显式地拼写出来。您发布的代码中的
完全是glibc版本中的
himagic=0x8080l
lomagic=0x01010101L

我看到的唯一区别是glibs版本使用了稍微不同的标准来检测零字节

if ((longword - lomagic) & himagic)
不执行
。&~longword
(与示例中的
HASZERO(x)
宏相比,它对
x
执行相同的操作,但也包括
~(x)
成员)显然,glibc的作者相信这个较短的公式更有效。但它可能导致误报。因此,他们在
if
下检查误报

这确实是一个有趣的问题,什么更有效:一个单阶段精确测试(您的代码)或两阶段测试,首先是粗略的不精确检查,然后是精确的第二次检查(glibc代码)


如果您想看看它们在实际性能方面的比较,请在您的平台和数据上计时。没有其他方法。

回答您的第二个问题,我认为基于字节的strlen实现如果智能且支持向量指令集,将使编译器实现更好的自动向量化已启用扩展(如SSE)(如使用
-msse
或适当的
-march
)。不幸的是,它不会导致基线CPU的任何矢量化,而基线CPU缺少这些功能,即使编译器可以生成32位或64位伪矢量化代码,如问题中引用的C代码,如果它足够聪明…

此外,请注意,此实现可以读取超过字符数组末尾的字符:

for (w = (const void *)s; !HASZERO(*w); w++);

因此依赖于未定义的行为。

注意,glibc源文件中的注释似乎是关于
#if 0
'd的代码,该代码比上述代码速度慢且精度略低(只有一个误报情况)。实际使用的代码(在
#else
情况下)在glibc中,源代码对除128以外的任何高字节都有误报。因此,我天真的结论是,glibc代码对ASCII文本的性能更好,但对任何高字节的文本的性能都要差得多。这是怎么回事?我们使用初始for循环对齐字大小,然后对“\0”逐字进行迭代字符数组必须以null结尾,否则就不好了将发生。我将使用不太迟钝的代码更新它例如:空的以null结尾的字符串是大小为1的字符数组。
*w
将从内存中读取4或8个字节,从而访问超过数组末尾的字节。在大多数平台上,这可以正常工作,但仍然是未定义的行为。Re:未定义的行为:另一个用户刚刚发布关于这一点的一个问题;请看。共识似乎是,这是未定义的行为,但编译器附带的
strlen
可以只依赖编译器保证的行为。另一个问题是,在C中这肯定是UB,但如果对齐指针,实际上可以在检查页面粒度的访问。(只要编译器在基于程序不包含UB的假设进行优化时没有得出任何不幸的结论…)
strlen
用asm手工编写的实现肯定可以做到这一点,但C不是asm。编译器仍然不会在循环进入之前对迭代计数未知的循环进行自动向量化。因此,不幸的是,搜索循环通常不会自动向量化。如果他们因为valgrind tha之类的原因选择不进行自动向量化,那真的很不幸t会抱怨读取超过了数组的末尾。但这不是唯一的原因,因为在静态数组(或作为
int-arr[static 1024]
传递的函数arg)中搜索时,仍然无法获得自动矢量化.刚刚检查了一个带有gcc和clang的
int
数组的简单搜索:哦,哇,ICC会自动将其矢量化..但是MSVC、gcc和clang在这个简单的情况下都会失败。对于非静态数组,ICC会到达对齐边界。不过valgrind仍然会不高兴。Related有一个解决类型punning UB的答案,一个d链接到glibc的手写asm,该asm实际上在大多数平台上使用。是的,x86 SIMD可以做得更好,比4或8更有效地处理16字节,并且没有误报。
for (w = (const void *)s; !HASZERO(*w); w++);