繁体   English   中英

实现memcmp

[英]Implementing memcmp

以下是memcmp的Microsoft CRT实现:

int memcmp(const void* buf1,
           const void* buf2,
           size_t count)
{
    if(!count)
        return(0);

    while(--count && *(char*)buf1 == *(char*)buf2 ) {
        buf1 = (char*)buf1 + 1;
        buf2 = (char*)buf2 + 1;
    }

    return(*((unsigned char*)buf1) - *((unsigned char*)buf2));
}

它基本上执行逐字节比较。

我的问题分为两部分:

  1. 是否有任何理由不通过int比较将此更改为int,直到count < sizeof(int) ,然后逐字节比较剩下的内容?
  2. 如果我做1,是否有任何潜在/明显的问题?

注意:我根本不使用CRT,所以无论如何我必须实现这个功能。 我只是在寻找有关如何正确实现它的建议。

如果您愿意,可以将其作为int-by-int比较或更广泛的数据类型。

你需要注意的两件事(至少是)在开始和结束时都是悬垂,以及两个区域之间的对齐方式是否不同。

如果您在不遵循其对齐规则的情况下访问值,某些处理器运行速度较慢(有些甚至会在您尝试时崩溃)。

因此,您的代码可能会进行char比较,直到int对齐区域,然后进行int比较,然后再次进行char比较,但同样, 两个区域的对齐可能很重要。

这些额外的代码复杂性是否值得您获得的节省取决于您无法控制的许多因素。 一种可能的方法是检测理想情况,其中两个区域对齐并以快速方式进行,否则只是逐个字符地进行。

您提出的优化非常常见。 最大的问题是,如果您尝试在不允许对单个字节以外的任何其他任何内容进行未对齐访问的处理器上运行它,或者在该模式下运行速度较慢; x86系列没有这个问题。

它也更复杂,因此更容易包含bug。

不要忘了,当你发现一个更大的块内的不匹配,则必须找出第一个不同的char在块 ,这样就可以计算出正确的返回值( memcmp()返回第一个字节不同的差异,视为unsigned char值)。

您找到的代码只是memcmp的调试实现,它针对简单性和可读性进行了优化,而不是针对性能进行了优化。

内在的编译器实现是特定于平台的并且足够智能以生成处理器指令,该指令在可能的情况下立即比较dwords或qwords(取决于目标架构)。 此外,如果两个缓冲区具有相同的地址(buf1 == buf2) ,则内部实现可以立即返回。 调试实现中也缺少此检查。

最后,即使你确切地知道你将在哪个平台上运行,完美的实现仍然不那么通用,因为它取决于一系列特定于你的程序其他部分的不同因素:

  • 什么是最小保证缓冲区对齐?
  • 你能否在不触发访问冲突的情况下读取缓冲区末尾的任何填充字节?
  • 缓冲参数可以相同吗?
  • 缓冲区大小可以为0吗?
  • 您是否只需要比较缓冲区内容是否相等? 或者你还需要知道哪一个更大(返回值<0或> 0)?
  • ...

如果性能是一个问题,我建议在汇编中编写比较例程。 大多数编译器都为您提供了一个选项,可以查看它们为源生成的组件。 您可以使用该代码并根据您的需求进行调整。

如果比较为int,则需要检查对齐并检查count是否可被sizeof(int)整除(将最后的字节作为char进行比较)。

这真的是他们的实施吗? 我还有其他问题,除了没有做到这一点:

  • 逐渐消失。
  • 返回声明是否有效? unsigned char - unsigned char = signed int?

int一次只能在指针对齐的情况下工作,或者如果你可以从每个指针的前面读取几个字节并且它们仍然是对齐的,那么如果两者在对齐边界之前都是1,那么你可以读取每个的一个字符然后去int-at-a-time,但是如果它们以不同方式对齐,例如一个是对齐的而另一个不是,则没有办法做到这一点。

当memcmp实际比较(它必须结束)并且数据很长时,它的效率最低(即它需要最长时间)。

我不会自己编写,但如果你要比较大部分数据,你可以做一些事情,比如确保对齐,甚至填充两端,然后如果你愿意的话,一次一个字。

另一个想法是优化处理器缓存和提取。 处理器喜欢在随机时间获取大块而不是单个字节。 虽然内部工作可能已经解释了这一点,但无论如何这将是一个很好的练习。 始终进行分析以确定最有效的解决方案。

Psuedo代码:

while bytes remaining > (cache size) / 2 do // Half the cache for source, other for dest.
  fetch source bytes
  fetch destination bytes
  perform comparison using fetched bytes
end-while
perform byte by byte comparison for remainder.

有关更多信息,请在Web上搜索“数据驱动设计”和“面向数据的编程”。

某些处理器(如ARM系列)允许条件执行指令(以32位,非拇指)模式。 处理器获取指令但仅在满足条件时才执行它们。 在这种情况下,尝试根据布尔赋值重新比较比较。 这也可以减少分支的数量,从而提高性能。

另请参阅循环展开
另请参见汇编语言

您可以通过将算法定制到特定处理器来获得大量性能,但在可移植性区域中会松散。

许多处理器将其实现为单个指令。 如果您可以保证运行的处理器可以使用一行内联汇编程序来实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM