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
std :: mismatch сделает это за вас вместе с std :: distance .
По сравнению с тем, что вы делаете, цикл обходится дешево: большие затраты будут связаны в первую очередь с извлечением данных из оперативной памяти (или с диска!).
Вы не можете избежать цикла при сравнении памяти, превышающей несколько байтов. Напишите алгоритм так, как вы можете его представить. Это достаточно просто, и вы можете быть поражены, насколько хорошо компилятор оптимизирует такой код.
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;
}
Если бы существовал лучший способ сравнения двух блоков памяти, для этого пришлось бы переопределить memcmp.
При этом часто memcmp имеет переносимую реализацию по умолчанию в стандартной библиотеке C, но часто она реализуется самим компилятором как встроенная функция. Эта встроенная функция должна быть сильно оптимизирована для целевой архитектуры, поэтому относитесь к реализации библиотеки с долей скептицизма.
Вам всегда понадобится петля. Но вы можете проверить, быстрее ли зацикливание на 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