2010-05-28 6 views
5

Je travaille actuellement dans une base de code où les adresses IPv4 sont représentées comme des pointeurs vers u_int8. L'opérateur d'égalité est mis en œuvre comme ceci:Comparaison rapide des tableaux char?

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

C'est probablement la jeûné solution, mais il provoque l'avertissement du compilateur GCC:

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

Comment puis-je réécrire correctement la comparaison sans enfreindre les règles strictes-aliasing et sans perdre des points de performance?

J'ai envisagé d'utiliser soit memcmp ou cette macro:

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

Je pense que la macro est la solution la plus rapide.

Que recommandez-vous?

Mise à jour
Je viens de lire l'article Squeezing performance out of memcmp usage qui explique comment le compilateur (Visual Studio, mais peut-être aussi CCG) peuvent optimiser !memcmp(..) appels.

+1

Avez-vous essayé les différentes options et les comparé pour voir lequel est vraiment le plus rapide? –

+0

@ Nick Meyer, pas encore, mais c'est une bonne suggestion. – StackedCrooked

Répondre

10

Je pencherais pour memcmp()

  1. Il est plus facile à transporter
  2. J'essaie généralement de ne pas être plus intelligent que mon compilateur/langue. Vous essayez de comparer le contenu de la mémoire et (en fonction des options du compilateur aussi) l'implémentation de memcmp() devrait être le moyen le plus efficace de le faire.

pense aussi que si votre compilateur ne memcmp en ligne() vous ne souffrirez pas le contexte de la fonction interrupteur

Etes-vous sûr que vous devez optimiser si difficile? Avez-vous déjà vérifié que votre programme passe le plus clair de son temps à faire ce genre d'opérations?

+2

Oui, 'std :: memcmp()' est ce que std lib a pour comparer des tableaux de built-ins. +1 de moi. Si le profilage montre qu'il est trop lent sur une certaine architecture, vous pouvez toujours revenir en arrière et le changer. J'en doute cependant. – sbi

+1

Être un bon programmeur , c'est savoir utiliser les outils fournis dans la boîte à outils standard. En outre, l'optimisation prématurée est la racine de tous les maux. Je sais que ces réponses ressemblent à des manuels, mais elles sont à la fois si importantes et sous-utilisées, même par les meilleurs d'entre nous, qu'elles méritent d'être répétées ... encore ... et encore ... – corsiKa

+1

Comparaison de l'adresse IP ' uint8' par 'uint8' est également portable. Une petite quantité de comparaisons est généralement plus efficace qu'un appel de fonction de bibliothèque; bien que seul le profilage ou une liste en langage assembleur montrera la preuve. –

3

La raison pour laquelle vous obtenez une erreur de la part de GCC est que tout élément dont la longueur est supérieure à 1 octet est aligné sur une adresse qui est un multiple de la taille de l'objet. Un entier de 32 bits aime démarrer sur des limites de 32 bits. Une variable char (signée, non signée ou simple), peut être sur n'importe quelle limite d'octets, comme 3 qui ne joue pas bien pour les extractions 32 bits par un processeur.

Dans votre cas, pour 4 octets (32 bits), il peut y avoir plus de préfixe en appelant memcmp que le code pour comparer réellement les octets.

Essayez ceci:

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

Regardez maman, le code de fonction membre sans utiliser this->! En ce qui concerne l'efficacité, ce code peut probablement être exécuté en même temps qu'un appel est fait à memcpy et le retour en est exécuté (sans exécuter le contenu de memcpy). Cela suppose que memcpy n'est pas incorporé. Sachant comment les bibliothèques de compilateurs sont écrites pour les cas génériques et grands, je soupçonne que ce code est encore plus petit et plus rapide qu'une version en ligne de memcpy.Bien que la preuve est d'imprimer une liste d'assemblage des deux versions et comparer.

Edit:
Note: déclarant la mise en œuvre en ligne ou de placer le code dans la déclaration de classe, sera mieux que la définition d'une macro dangereuse. Ce sera plus sûr et contiendra la même quantité de code. J'aime la version en ligne, car elle est plus lisible et plus facile à maintenir.

Questions connexes