2010-05-28 15 views
5

Actualmente estoy trabajando en una base de código donde las direcciones IPv4 se representan como punteros a u_int8. El operador de igualdad se implementa como esto:Comparación rápida de matrices de caracteres?

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

Esta es probablemente la solución de ayuno, pero hace que la advertencia compilador GCC:

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

¿Cómo puedo volver a escribir la comparación correctamente sin romper las reglas estrictas-aliasing y sin perder puntos de rendimiento?

me han considerado el uso de cualquiera o memcmp esta macro:

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

Estoy pensando que la macro es la solución más rápida.

¿Qué me recomiendas?

actualización
acabo de leer el artículo de Squeezing performance out of memcmp usage que explica como el compilador (Visual Studio, pero quizás también GCC) pueden optimizar !memcmp(..) llamadas.

+1

¿Has probado las diferentes opciones y las has comparado para ver cuál es realmente el más rápido? –

+0

@Nick Meyer, aún no, pero es una buena sugerencia. – StackedCrooked

Respuesta

10

Yo iría por memcmp()

  1. Es más portátil
  2. Por lo general trato de no ser más inteligente que mi compilador/idioma. Está intentando comparar los contenidos de la memoria y (dependiendo también de las opciones del compilador) la implementación de memcmp() debería ser la forma más eficiente de hacerlo.

también piensan que si su compilador no coloca en línea memcmp() que van a sufrir cambiar el contexto de la función

¿Seguro que necesita para optimizar tan difícil? ¿Ya ha comprobado que su programa pasa la mayor parte del tiempo haciendo ese tipo de operaciones?

+2

Sí, 'std :: memcmp()' es lo que tiene la biblioteca estándar para comparar matrices de complementos. +1 de mi parte Si la creación de perfiles muestra que es demasiado lenta en una determinada arquitectura, siempre puede volver y modificarla. Sin embargo, lo dudo. – sbi

+1

Ser un buen programador de significa saber cómo usar las herramientas provistas en el kit de herramientas estándar. Además, la optimización prematura es la raíz de todo mal. Sé que suenan como respuestas de libros de texto, pero ambos son tan importantes y poco utilizados, incluso por los mejores de nosotros a veces, que vale la pena repetir ... una y otra vez ... – corsiKa

+1

Comparando la dirección IP ' uint8' by 'uint8' también es portátil. Una pequeña cantidad de comparaciones suele ser más eficiente que una llamada a función de biblioteca; aunque solo los perfiles o una lista de idiomas ensamblados mostrarán la prueba. –

3

La razón por la que está recibiendo un error de GCC es que todo lo que tiene más de 1 byte de longitud le gusta estar alineado con una dirección que es un múltiplo del tamaño del objeto. A un entero de 32 bits le gusta comenzar en límites de 32 bits. Una variable char (firmada, sin firmar o simple), puede estar en cualquier límite de bytes, como 3, que no funciona bien para las recuperaciones de 32 bits de un procesador.

En su caso, para 4 bytes (32 bits), puede haber más sobrecarga al llamar al memcmp que el código para comparar realmente los bytes.

Prueba esto:

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]; 
} 

Mire a la mamá, el código de función miembro sin necesidad de utilizar this->!

En cuanto a la eficiencia, este código probablemente se puede ejecutar al mismo tiempo que se realiza una llamada a memcpy y la devolución se ejecuta desde allí (sin ejecutar el contenido de memcpy). Esto supone que memcpy no está alineado. Sabiendo cómo se escriben las librerías de compilación para los casos genéricos y grandes, sospecho que este código es aún más pequeño y más rápido que una versión en línea de memcpy.Aunque la prueba es imprimir una lista de ensamblaje de las dos versiones y comparar.

Editar:
Nota: declarar la implementación como en línea o colocar el código en la declaración de clase, será mejor que la definición de una macro peligroso. Será más seguro y contendrá la misma cantidad de código. Me gusta la versión del método en línea porque es más fácil de leer y de mantener.

Cuestiones relacionadas