2 votes

Permutation des endians lors de l'utilisation du cast de réinterprétation

Lors de l'envoi de données via le réseau, la conversion des données en octets peut se faire de plusieurs manières :

12345  --> {0 0 48 57}

typedef unsigned char byte;

//1. Bit shift
int32_t shiftedInteger =  (int32_t) (inBytes[0] << 24 | inBytes[1] << 16  | 
inBytes[2] << 8 | inBytes[3]);

//2. Reinterpret cast
int32_t reinterpretedInteger = *reinterpret_cast<int32_t*>(&inBytes);

//3. Using unions
union{
    byte b[4];
    int32_t i;
}unionCast;

memcpy(unionCast.b,inBytes,4);
int_32t unionCasted = unctionCast.i;

Quelle est la meilleure façon de convertir les données (utilisation sur un microprocesseur de type arduino) ?

Les méthodes union et reinterpretCast sont confrontées au problème des grands et petits endians, mais elles s'avéreront utiles pour travailler avec des nombres à virgule flottante, car de simples décalages de bits ne suffiront pas à reconvertir les données. Comment puis-je permuter les endians lorsque j'utilise la méthode reinterpret_cast ?

1voto

Yakk Points 31636

Votre utilisation de reinterpret et l'accès aux membres inactifs de union violent tous deux la norme. Les règles qui le stipulent sont connues sous le nom d'aliasing strict.

Donc, parmi vos options, le déplacement est le seul à être conforme aux normes.

Une option supplémentaire -- memcpy directement dans le type cible -- est également conforme à la norme.

Vous pouvez faire en place légalement par memcpy à un tableau de pile, placement new bew tyoe, puis memcpy retour. L'optimiseur éliminera les memcpys !

Tu pourrais même faire ça :

template<class T> 
struct raw_bytes:
  std::array<char, sizeof(T)>
{
  static_assert(std::is_pod<T>::value, "pod only");
  static raw_bytes to_raw( T in ){
    raw_bytes r;
    std::memcpy( r.data(), std::addressof(in), sizeof(T) );
    return r;
  }
  // this object no longer valid after convert, but returned reference is until this object destroyed
  T& convert(){
    char tmp[sizeof(T)];
    memcpy(tmp, data(), sizeof(T));
    T* r= ::new( (void*)data() ) T;
    memcpy(r, tmp, sizeof(T));
    return *r;
  }
};

qui peut ou non en valoir la peine.

Vous pouvez coller un raw_bytes dans une structure et y injecter des octets. Ensuite, vous pouvez convert() ces octets en place pour T . La référence retournée est le seul moyen d'accéder légalement à ces octets ; les méthodes de l'option raw_bytes ne sont plus légales selon une lecture stricte de la norme.

0voto

Sorin Points 1606

Vous ne pouvez pas. Le cast de réinterprétation change seulement le type que le compilateur utilise, il ne touche pas les données.

Comme suggéré dans Comment convertir les valeurs big-endian et little-endian en C++ ? Utilisez

int32_t __builtin_bswap32 (int32_t x)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X