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:
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); }