2010-05-28 3 views
5

В настоящее время я работаю в кодовой базе, где адреса IPv4 представлены в виде указателей на u_int8. Оператор равенства реализуется следующим образом:Быстрое сравнение массивов символов?

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return (*(u_int32*) this->myBytes == *(u_int32*) inAddress); 
} 

Это, вероятно, постились решение, но оно вызывает предупреждение GCC компилятора:

ipv4address.cpp:65: warning: dereferencing type-punned pointer will break strict-aliasing rules 

Как я могу переписать сравнение корректно, не нарушая правил строгого сглаживания и без потери очков производительности?

Я рассматривал возможность использования либо memcmp этого макроса:

#define IS_EQUAL(a, b) \ 
    (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) 

Я думаю, что макрос является самым быстрым решением.

Что вы рекомендуете?

Update
Я только что прочитал статью Squeezing performance out of memcmp usage, которая объясняет, как компилятор (Visual Studio, но также, возможно, GCC) может оптимизировать !memcmp(..) вызовы.

+1

Вы пробовали разные варианты и сравнивали их, чтобы увидеть, что на самом деле самое быстрое? –

+0

@ Ник Майер, еще нет, но это хорошее предложение. – StackedCrooked

ответ

10

Я хотел бы пойти на memcmp()

  1. Это более портативный
  2. Я обычно стараюсь не быть умнее, чем мой компилятор/язык. Вы пытаетесь сравнить содержимое памяти и (в зависимости от параметров компилятора), реализация memcmp() должна быть наиболее эффективным способом сделать это.

думаю также, что если ваш компилятор не встраивать memcmp() вы будете страдать от контекста функция переключения

Вы уверены, что вам нужно оптимизировать, что трудно? Вы уже проверили, что ваша программа проводит большую часть времени, выполняя этот тип операций?

+2

Yep, 'std :: memcmp()' это то, что std lib имеет для сравнения массивов встроенных модулей. +1 от меня. Если профилирование показывает, что он слишком медленный для определенной архитектуры, вы всегда можете вернуться и изменить его. Я в этом сомневаюсь. – sbi

+1

Будучи хорошим программистом , он знает, как использовать инструменты, предусмотренные в стандартном наборе инструментов. Кроме того, преждевременная оптимизация - это корень всего зла. Я знаю, что они звучат как ответы на учебники, но они оба настолько важны и недостаточно используются даже лучшими из нас порой, что их стоит повторять ... снова ... и снова ... – corsiKa

+1

Сравнивая IP-адрес ' uint8' by 'uint8' также переносится. Небольшое количество сравнений обычно более эффективно, чем вызов функции библиотеки; хотя показ доказательств будет только в профилировании или листинге на ассемблере. –

3

Причина, по которой вы получаете сообщение об ошибке GCC, состоит в том, что все, что больше 1 байта в длину, должно быть выровнено с адресом, кратным размеру объекта. 32-разрядное целое любит начинать с 32-битных границ. A char переменная (подписанная, без знака или обычная) может находиться на любой границе байта, например 3, которая не играет хорош для 32-битных выборок процессором.

В вашем случае для 4 байтов (32 бит) может быть больше накладных расходов при вызове memcmp, чем код для фактического сравнения байтов.

Попробуйте это:

bool Ipv4Address::operator==(const u_int8 * inAddress) const 
{ 
    return myBytes[0] == inAddress[0] 
     && myBytes[1] == inAddress[1] 
     && myBytes[2] == inAddress[2] 
     && myBytes[3] == inAddress[3]; 
} 

Смотри мама, код функции члена без использования this->!

Что касается эффективности, этот код, вероятно, может быть выполнен в то же самое время, когда выполняется вызов memcpy и выполненный от него возврат (без выполнения содержимого memcpy). Предполагается, что memcpy не является встроенным. Зная, как библиотеки компиляторов написаны для общих и больших случаев, я подозреваю, что этот код все еще меньше и быстрее, чем встроенная версия memcpy.Хотя доказательство состоит в том, чтобы распечатать список сборок двух версий и сравнить.

Edit:
Примечание: объявление реализации как инлайн или размещать код в объявлении класса, будет лучше, чем определение опасного макроса. Он будет более безопасным и содержать то же количество кода. Мне нравится версия встроенного метода, потому что она более читабельна и удобна в обслуживании.