définir le bit le plus significatif en C

J’essaye de placer le bit le plus significatif dans un long long unsigned, x. Pour ce faire, j’utilise cette ligne de code:

x |= 1<<((sizeof(x)*8)-1); 

Je pensais que cela devrait fonctionner, parce que sizeof donne la taille en octets. J’ai donc multiplié par 8 et soustrait un pour définir le bit final. Chaque fois que je fais cela, le compilateur a cet avertissement: “warning: compte de décalage à gauche> = largeur de type”

Je ne comprends pas pourquoi cette erreur se produit.

Le 1 que vous décalez est une constante de type int , ce qui signifie que vous décalez une valeur int par sizeof(unsigned long long) * 8) - 1 bits. Ce décalage peut facilement dépasser la largeur de int , ce qui est apparemment ce qui s’est passé dans votre cas.

Si vous souhaitez obtenir un masque de masque binary de type unsigned long long , vous devez commencer par un masque binary initial de type unsigned long long et non de type int .

 1ull << (sizeof(x) * CHAR_BIT) - 1 

Un meilleur moyen de construire le même masque serait

 ~(-1ull >> 1) 

ou

 ~(~0ull >> 1) 

utilisez 1ULL << au lieu de 1 <<

Utiliser seulement “1” vous fait décaler un entier. 1ULL sera un long non signé qui est ce dont vous avez besoin. Un entier fera probablement 32 bits et long long probablement 64 bits. Donc changeant:

 1 << ((sizeof(long long)*8)-1) 

sera (très probablement):

 1 << 63 

Puisque 1 est un entier qui est (très probablement) 32 bits, vous recevez un avertissement car vous essayez de dépasser la valeur MSB d'une valeur de 32 bits.

Le littéral 1 vous déplacez n’est pas automatiquement un unsigned long long (mais un int ) et n’a donc pas autant de bits que nécessaire. Suffixez-le avec ULL (c’est-à-dire, 1ULL ) ou 1ULL en unsigned long long avant de passer au type correct.

Aussi, pour être un peu plus sûr pour les plateformes étranges, remplacez 8 par CHAR_BIT . Notez que ce n’est toujours pas nécessairement la meilleure façon de définir le bit le plus significatif. Voir, par exemple, cette question pour des alternatives.

Vous devez également envisager d’utiliser un type tel que uint64_t si vous supposez que unsigned long long à une certaine largeur, ou uint_fast64_t / uint_fast64_t si vous avez besoin d’au moins une certaine largeur ou uintmax_t si vous avez besoin du type disponible le plus grand.

Grâce à la représentation du complément à 2 des nombres entiers négatifs, l’interger le plus négatif est exactement le modèle de bits souhaité avec uniquement le jeu de bits de poids fort. Donc x |= (unsigned long long )LONG_LONG_MIN; devrait fonctionner aussi.