Je suis actuellement en train d'implémenter CBOR et j'ai besoin à plusieurs reprises de lire 1, 2, 4 ou 8 octets à partir d'un tableau d'octets qui doivent ensuite être combinés en un type entier de 1, 2, 4 ou 8 octets.Type d'octet en nombre entier: décalage et ajout ou conversion implicite à travers une union?
Pour le 4 cas d'octets, j'utilise actuellement cette fonction de modèle (vec
est le vecteur d'octet Je lis, current_idx
marque la position dans le vecteur d'où je veux commencer à lire 4 octets):
template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
return static_cast<T>((static_cast<T>(vec[current_idx]) << 030) +
(static_cast<T>(vec[current_idx + 1]) << 020) +
(static_cast<T>(vec[current_idx + 2]) << 010) +
static_cast<T>(vec[current_idx + 3]));
}
(I ont trois fonctions similaires pour le cas de 1, 2, et 8 octets, respectivement.)
Un appel d'exemple serait
std::vector<uint8_t> vec {0x01, 0x00, 0x00, 0xff};
auto num = get_from_vector<uint32_t>(vec, 0);
assert(num == 0x10000FF);
performances Bien que ne semble pas la question ici, mais je me demande quand même si le code suivant peut être plus efficace ou au moins plus lisible:
template<typename T, typename std::enable_if<sizeof(T) == 4, int>::type = 0>
static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_idx)
{
union U
{
T result_type;
uint8_t bytes[4];
} u;
u.bytes[3] = vec[current_idx];
u.bytes[2] = vec[current_idx + 1];
u.bytes[1] = vec[current_idx + 2];
u.bytes[0] = vec[current_idx + 3];
return u.result_type;
}
Toute réflexion sur ce sujet?
L'utilisation d'un syndicat pour le type calembour fonctionne en général, mais est UB, si cela est important pour vous. Sur un autre point, c'est la première utilisation raisonnable que j'ai vu des octals depuis longtemps;) –
Ce type d'utilisation d'Union est UB comme l'a dit @ IanM_Matrix1. Mais cela fonctionnera avec la plupart des compilateurs. Si je ne me trompe pas, le document de GCC fait même une mention explicite de l'utilisation de l'union pour le type punting, qui est traité comme une exception de ce type d'UB. –
pourquoi ne pas avoir juste quelque chose comme 'T résultat; uint8_t * res_ptr = reinterpret_cast (& résultat); * résultat ++ = vec [current_idx + 3]; ... '? –
akappa