Memory comparison (with difference position)

Is there a way to compare two blocks of memory, and know at which point they differ (memcmp() does not meet this requirement)? I wouldn't want to perform costly loops. Thanks in advance.

Regards, Neo_b

8
задан S.L. Barth - Reinstate Monica 17 July 2012 в 15:19
поделиться

6 ответов

std :: mismatch сделает это за вас вместе с std :: distance .

4
ответ дан 5 December 2019 в 15:16
поделиться

По сравнению с тем, что вы делаете, цикл обходится дешево: большие затраты будут связаны в первую очередь с извлечением данных из оперативной памяти (или с диска!).

2
ответ дан 5 December 2019 в 15:16
поделиться

Вы не можете избежать цикла при сравнении памяти, превышающей несколько байтов. Напишите алгоритм так, как вы можете его представить. Это достаточно просто, и вы можете быть поражены, насколько хорошо компилятор оптимизирует такой код.

2
ответ дан 5 December 2019 в 15:16
поделиться

memcmp просто выполняет «дорогостоящий цикл», байт за байтом. Например, вот реализация Microsoft:

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;
}
2
ответ дан 5 December 2019 в 15:16
поделиться

Если бы существовал лучший способ сравнения двух блоков памяти, для этого пришлось бы переопределить memcmp.

При этом часто memcmp имеет переносимую реализацию по умолчанию в стандартной библиотеке C, но часто она реализуется самим компилятором как встроенная функция. Эта встроенная функция должна быть сильно оптимизирована для целевой архитектуры, поэтому относитесь к реализации библиотеки с долей скептицизма.

1
ответ дан 5 December 2019 в 15:16
поделиться

Вам всегда понадобится петля. Но вы можете проверить, быстрее ли зацикливание на 4 байта (приведение к int*) или на 8 байтов (uint64_t или long long int), чем наивное решение для каждого байта.

Более того, в зависимости от длины (скажем,> 1 КБ) вы можете развернуть цикл, то есть проверить, например, per 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&0xff == m2&0xff == 0

0
ответ дан 5 December 2019 в 15:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: