Le moyen le plus efficace de lire UInt32 depuis n’importe quelle adresse mémoire?

Quel serait le moyen le plus efficace de lire une valeur UInt32 à partir d’une adresse mémoire arbitraire en C ++? (En supposant une architecture Windows x86 ou Windows x64.)

Par exemple, pensez à avoir un pointeur d’octets qui pointe quelque part en mémoire pour bloquer ce qui contient une combinaison d’ints, de données de chaîne, etc., tous mélangés. L’exemple suivant montre la lecture des différents champs de ce bloc dans une boucle.

typedef unsigned char* BytePtr; typedef unsigned int UInt32; ... BytePtr pCurrent = ...; while ( *pCurrent != 0 ) { ... if ( *pCurrent == ... ) { UInt32 nValue = *( (UInt32*) ( pCurrent + 1 ) ); // line A ... } pCurrent += ...; } 

Si à la ligne A , pPtr arrive à contenir une adresse alignée sur 4 octets, la lecture de l’UInt32 doit être une lecture de mémoire unique. Si pPtr contient une adresse non alignée, plusieurs cycles de mémoire peuvent être nécessaires, ce qui ralentit le code. Existe-t-il un moyen plus rapide de lire la valeur des adresses non alignées?

Je recommande memcpy dans un temporaire de type UInt32 dans votre boucle.

Cela tire parti du fait qu’un memcpy de quatre octets sera incorporé par le compilateur lors de la création avec l’optimisation activée et présente quelques autres avantages:

  • Si vous êtes sur une plate-forme où l’alignement compte (hpux, solaris sparc, …), votre code ne va pas être pris au piège.
  • Sur une plate-forme où l’alignement est important, il peut être utile d’effectuer une vérification d’adresse pour l’alignement, puis une vérification d’une charge alignée normale ou d’un ensemble de charges et de bits de 4 octets. La mémoire de votre compilateur va très probablement le faire de manière optimale.
  • Si vous êtes sur une plate-forme où un access non aligné est autorisé et ne nuit pas aux performances (x86, x64, powerpc, …), vous êtes plutôt sûr qu’un tel jeu va être le moyen le moins coûteux de le faire. access.
  • Si votre mémoire était initialement un pointeur vers une autre structure de données, votre code peut être indéfini en raison de problèmes d’alias, car vous convertissez à un autre type et déréférencement de cette dissortingbution. Les problèmes de temps d’exécution dus à des problèmes d’optimisation liés aux alias sont très difficiles à détecter! En supposant que vous pouvez les comprendre, la correction peut également être très difficile dans le code établi et vous devrez peut-être utiliser des options de compilation obscures comme -fno-ssortingct-aliasing ou -qansialias, ce qui peut limiter considérablement la capacité d’optimisation du compilateur.

Votre code est un comportement indéfini.

A peu près la seule solution “correcte” est de ne lire que quelque chose comme un type T s’il s’agit d’ un type T , comme suit:

 uint32_t n; char * p = point_me_to_random_memory(); std::copy(p, p + 4, reinterpret_cast(&n)); std::cout << "The value is: " << n << std::endl; 

Dans cet exemple, vous voulez lire un entier et le seul moyen d'y parvenir est d' avoir un entier. Si vous voulez qu'il contienne une certaine représentation binary, vous devez copier ces données à l'adresse commençant au début de la variable.

Laisser le compilateur faire l’optimisation!

 UInt32 ReadU32(unsigned char *ptr) { return static_cast(ptr[0]) | (static_cast(ptr[1])<<8) | (static_cast(ptr[2])<<16) | (static_cast(ptr[3])<<24); }