C++: Comment puis-je jeter un int à un unsigned long et de ne pas changer tous les bits?
C++: Comment puis-je jeter un int à un unsigned long et de ne pas changer tous les bits?
Je veux emballer et déballer des valeurs dans la mémoire. Le mot de la taille est de 64 bits.
Cet extrait illustre bien le problème:
int v1 = -2; //0xfe
unsigned long v2=(unsigned long)v1; //0xfffe, I want 0x00fe
La solution est simple:
unsigned long v2=(unsigned int)v1; //0x00fe
Toutefois, ce code est dans un modèle où le type de cible est un paramètre, j'ai donc dû recourir à cette:
uint64 target = mem[index] & mask;
uint64 v;
if (value < 0) {
switch (bits) {
case 8:
v = (uint8)value;
break;
case 16:
v = (uint16)value;
break;
case 32:
v = (uint32)value;
break;
}
} else {
v = value;
}
v = v << lShift;
target |= v;
mem[index] = target;
Supposons, par exemple, le type de "valeur" est un int (16 bits) et les bits=16.
Le but est de masquer les bits dans la mémoire de valeur et de les remplacer.
Quelqu'un sait-il un moyen plus facile?
Vous avez une taille de mot de 64 bits et int 16? C'est spécial.
Qu'est-ce que la signature de la méthode? Vous ne donner que des informations partielles ainsi seulement s'attendre à une partie de la bonne solution. Mais je soupçonne que vous pouvez utiliser boost::type_traits pour vous aider.
La façon dont vous le faites n'est pas portable. Si vous souhaitez conserver les bits de façon portable, vous avez besoin de recourir à type de beaucoup les jeux de mots:
Qu'est-ce que la signature de la méthode? Vous ne donner que des informations partielles ainsi seulement s'attendre à une partie de la bonne solution. Mais je soupçonne que vous pouvez utiliser boost::type_traits pour vous aider.
La façon dont vous le faites n'est pas portable. Si vous souhaitez conserver les bits de façon portable, vous avez besoin de recourir à type de beaucoup les jeux de mots:
unsigned long v2= *(unsigned int*)&v1;
. Sinon vous avez un conversion de valeur, qui est autorisé à modifier des bits en fonction du signe de la représentation.
OriginalL'auteur Michael Fitzpatrick | 2011-08-05
Vous devez vous connecter pour publier un commentaire.
En supposant que vous avez le C++0x support:
Je suis en supposant que vous êtes le paramétrage du type de
value
, sinon cela n'a aucun sens.EDIT: C++-ish en utilisant
static_cast
au lieu d'un C cast. Je suppose que c'est ce qui m'a un downvote.OriginalL'auteur MSN
Si vous n'avez pas l'esprit de la saisie, un trait de classe vient à l'esprit:
Utilisation:
Mise à jour: Encore plus simple, vous avez juste à faire un tas de surcharges:
2e mise à jour: vous devriez probablement Vous dire
static_cast<T>(x)
plutôt que(T)(x)
si vous voulez être encore plus similaire à C++.Cela a l'air vraiment prometteur puisque le compilateur est en train de faire le travail que mon exemple n'est au moment de l'exécution. Ainsi, au lieu de l'expression "si (valeur < 0)" je vais ajouter "v = ToULong<IntType> ();" où "IntType" le type de la valeur de la variable.
Vous devez appeler la fonction membre statique,
ToULong<IntType>::get(value)
-- mais je pense que les surchargées gratuit fonctions aussi bien et ils sont un peu plus simple sur le plan conceptuel. Le trait de classe vous donne un peu de type supplémentaire de sécurité, parce que les fonctions libres peuvent également travailler pour (sans ambiguïté) implicitement convertible types, qui peuvent être inattendus.OriginalL'auteur Kerrek SB
Comment au sujet de l'union?
Velthuis Veuillez noter
stub
membre.Oh, OK, je vois maintenant.
OriginalL'auteur outmind
À l'aide de l'idée avancée par "Kerrek SB" je suis venu avec une solution.
L'aide de ce concept, j'ai été en mesure d'apporter d'autres améliorations au code.
Par exemple, l'appel à vectorItemMask() est maintenant templateized aussi.
OriginalL'auteur Michael Fitzpatrick
De jeter sans changer les bits de prendre une référence, puis de déréférencement avec le type approprié:
Cela suppose que les tailles sont les mêmes. Il a un comportement indéfini si sizeof(int) != sizeof(unsigned long). Vous voulez probablement unsigned int.
Edit: réalisé que j'ai répondu à une fausse question.
Boost type_traits a quelque chose (je crois que c'est make_unsigned) pour convertir un type int pour la version non signée (si elle est signée) et ne rien faire si ce n'est pas signé.
int*
àunsigned long*
et de déférence est un comportement indéterminé si je me souviens bien.Avec certains compilateurs, int et unsigned long ont la même taille, ce qui signifie il n'y a pas un comportement indéfini. Ce qui est parfaitement analogue à un syndicat.
Sauf qu'elle ne se stricte aliasing règles. D'accéder à un type par l'intermédiaire d'un pointeur vers un autre type UB.
*reinterpret_cast<unsigned long *>&v1 UB?
Le reinterpret_cast devra être définie par l'implémentation. Sinon, nous ne savons pas ce qu'il fait. Le standard laisse la conversion entre les différents types de pointeur jusqu'à la mise en œuvre.
OriginalL'auteur Foo Bah
Je crois que vous pourriez utiliser un bit à bit ET pour obtenir le résultat souhaité.
Et vous obtenez toujours une promotion à un type commun avant en faisant de l'op.
OriginalL'auteur Puppy