【问题标题】:Memory comparison (with difference position)内存比较(有差异位置)
【发布时间】:2010-08-24 22:23:23
【问题描述】:

有没有办法比较两个内存块,并知道它们在哪一点不同(memcmp() 不满足这个要求)?我不想执行昂贵的循环。提前致谢。

问候,Neo_b

【问题讨论】:

  • 另请参阅stackoverflow.com/questions/855895/intrinsic-memcmp,了解 per-cpu 优化的 memcmp 实现。如果您知道 CPU,您可以根据需要调整 gcc 的 __builtin_memcmp() 函数之一。
  • 请注意,您在此处所拥有的任何东西都将被实现为一个循环somewhere -- 如果没有一个循环,就没有什么神奇的方法可以在这里做您想做的事情。

标签: c++ memory position compare


【解决方案1】:

std::mismatch 将与std::distance 一起为您执行此操作。

【讨论】:

  • 你假设他使用的是 STL 迭代器,而且他需要知道内存在哪一点不同。
  • 我先有 std::equal ,这显然是错误的,所以我已经更正了。算法与指针以及(成熟的)迭代器一起工作得非常好。
  • @Doomsday: char* 一个迭代器类型,mismatch 确实返回两​​个指向差异的迭代器。 +1
  • @Doomsday:为了更好地阐明其他评论者所说的话,所有 STL 算法都使用纯指针,而不仅仅是迭代器。
  • 呃,我最初的评论是关于 std::equal,而不是 std::mismatch。我对不匹配的解决方案很好。
【解决方案2】:

与您正在做的任何其他事情相比,循环很便宜:首先要从内存(或磁盘!)中检索数据。

【讨论】:

    【解决方案3】:

    您无法避免循环使用超过几个字节的内存比较。写出你可以想象的算法。这很简单,您可能会惊讶于编译器对这样的代码的优化程度。

    【讨论】:

      【解决方案4】:

      memcmp 只是做一个“昂贵的循环”,一个字节一个字节。例如,这里是微软的实现:

      EXTERN_C int __cdecl memcmp(const void *Ptr1, const void *Ptr2, size_t Count)
      {
          INT v = 0;
          BYTE *p1 = (BYTE *)Ptr1;
          BYTE *p2 = (BYTE *)Ptr2;
      
          while(Count-- > 0 && v == 0) {
              v = *(p1++) - *(p2++);
          }
      
          return v;
      }
      

      大多数其他实现都做同样的事情。根据您的需要,您可以执行以下操作:

      long my_memcmp(const void *Ptr1, const void *Ptr2, size_t Count)
      {
          INT v = 0;
          long pos = 0;
          BYTE *p1 = (BYTE *)Ptr1;
          BYTE *p2 = (BYTE *)Ptr2;
      
          while(Count-- > 0 && v == 0) 
          {
              v = *(p1++) - *(p2++);
              if (v == 0)
                  pos++;
              else
                  break;
          }
      
          return pos;
      }
      

      【讨论】:

      • byte-per-byte 确实很昂贵。 32 位 int 运算甚至可能比 8 位运算更快。
      • 我创建了自己的实现(我想我最终可以用其他东西代替它)。我的需求需要多达 10 000 000 次迭代。系统有时会冻结,但它可以工作。它还说明在第一次不匹配发生后有多少字节不匹配。
      • @Neo_b:1000 万次迭代并不多——大多数系统都会在四分之一秒或更短的时间内完成。我会查看你的输入缓冲方案,或者考虑重新考虑你是如何解决这个问题的。例如,如果您正在搜索字符串,那么 Boyer Moore 算法可能会比这里的任何东西都做得更好。
      • 我实际上是在检查两个图像(或其部分)是否相同(对于我的远程桌面服务器)。无需发送未更改的内容,对吗? :)
      • 您不想要一个算法来返回所有更改的字节,而不仅仅是更改字节的第一个位置吗?
      【解决方案5】:

      如果有更好的方法来比较两个内存块,memcmp 将被重新实现。

      话虽如此,memcmp 在标准 C 库中有一个默认的可移植实现,但通常由编译器本身作为内置函数实现。这个内置函数应该针对目标架构进行了高度优化。因此,对库实现稍加注意。

      【讨论】:

        【解决方案6】:

        你总是需要一个循环。但是如果循环 4 字节(转换为 int*)或 8 字节(uint64_tlong long int)比简单的每字节解决方案更快,您可以进行基准测试。

        更好的是,根据长度(例如,>1kb),您可以展开循环,这意味着您检查例如每 8 个 int/uint64_t 并在不匹配时精确定位第一个不同的字节。

        uint64_t *bigsteps1 = (uint64_t*)m1;
        uint64_t *bigsteps2 = (uint64_t*)m2;
        int steps = min(m1_len,m2_len)/sizeof(uint64_t);
        int i;
        for ( i=0; i<steps; i+=8 )
        {
            if ( bigsteps1[i]   != bigsteps2[i]
              || bigsteps1[i+1] != bigsteps2[i+1]
           /// ....
              || bigsteps1[i+7] != bigsteps2[i+7] ) break;
        }
        
        // i<steps tells if we found a difference
        // end game is trivial, left as an excercise to the reader.
        

        循环展开也可能适得其反,因为你有所有这些 +N 的东西,还有 i+=8。确定基准。

        ps 还要检查内存对齐:m1&amp;0xff == m2&amp;0xff == 0 时这将是最快的

        【讨论】:

        • 感谢您的建议,我肯定会实施它,虽然我不完全确定 m1&0xff == m2&0xff == 0 应该做什么,据我所知 m1&0xff == m1,是对不对?
        • 这在某些情况下会更快,但可能会导致一些问题。首先,它依赖于您的平台对 64 位整数的对齐方式与对字符的对齐方式相同,但通常情况并非如此。 (没有人说字符数组的基数必须在 8 字节边界上)其次,内置的内在函数或汇编程序可能会更快。在 x86 上,内存对齐问题只会让事情变慢,而在其他架构上,它会导致处理器抛出中断。
        • @Neo_b: m1&amp;0xff == 0 是测试地址m1 是否以00 结尾。 @Billy:当然,在这些优化中,你必须稍微调整边界,所以直到第一个对齐的块你测试得很慢,然后尽可能快地测试尽可能多的块,然后慢慢地测试剩余的块。 (如前所述,这些事情只有在块足够大的情况下才能积极发挥作用)内置的内在函数或汇编程序可能会更快如果它存在,我认为手头的问题不是这种情况。
        • 哦,对了,我的错误(之前不带零的 0xff 不知何故不合逻辑地欺骗了我认为 m1 是一个字节)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 2015-08-08
        相关资源
        最近更新 更多