实现memcmp

时间:2011-02-16 14:31:58

标签: c++ c 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,是否有任何潜在/明显的问题?
  3. 注意:我根本没有使用CRT,所以无论如何我必须实现这个功能。我只是在寻找有关如何正确实现它的建议。

8 个答案:

答案 0 :(得分:6)

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

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

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

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

额外的代码复杂性是否值得您获得的节省取决于您控制之外的许多因素。一种可能的方法是检测理想的情况,即两个区域的排列方式相同,并以快速的方式进行,否则只需按字符进行。

答案 1 :(得分:5)

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

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

答案 2 :(得分:1)

不要忘记,当您在较大的块中发现不匹配时,您必须在块中识别该块中的第一个不同的char ,以便您可以计算正确的返回值( memcmp()返回第一个不同字节的差异,视为unsigned char值。)

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

  • castng away constness。
  • 返回声明是否有效? unsigned char - unsigned char = signed int?

int一次仅在指针对齐时才有效,或者如果你可以从每个指针的前面读取几个字节并且它们仍然是对齐的,那么如果在对齐边界之前两者都是1,你可以读取一个char然后每个都进行一次,但是如果它们以不同的方式对齐,例如一个是对齐而另一个不对齐,则无法执行此操作。

memcmp在实际比较时效率最低(即花费时间最长)(它必须结束)并且数据很长。

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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位,非拇指)模式。处理器获取指令但仅在满足条件时才执行它们。在这种情况下,尝试根据布尔赋值重新比较比较。这也可以减少分支的数量,从而提高性能。

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

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

答案 7 :(得分:0)

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

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

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

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

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