Qu'est-ce que CHAR_BIT?

91

Citant le code pour calculer la valeur absolue entière (abs) sans branchement de http://graphics.stanford.edu/~seander/bithacks.html :

int v;           // we want to find the absolute value of v
unsigned int r;  // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1;

r = (v + mask) ^ mask;

Variante brevetée:

r = (v ^ mask) - mask;

Qu'est-ce que c'est CHAR_BITet comment l'utiliser?

dato datuashvili
la source

Réponses:

-2

Vous devez être conscient que ce code dépend du comportement défini par l'implémentation du décalage de bits à droite sur les types signés. gcc promet de toujours donner le bon comportement (signe-bit-extension) mais ISO C permet à l'implémentation de remplir à zéro les bits supérieurs.

Une façon de contourner ce problème:

#ifdef HAVE_SIGN_EXTENDING_BITSHIFT
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
#else
int const mask = -((unsigned)v >> sizeof(int) * CHAR_BIT - 1);
#endif

Votre Makefileou config.hetc. peut définir HAVE_SIGN_EXTENDING_BITSHIFTau moment de la construction en fonction de votre plate-forme.

R .. GitHub STOP AIDING ICE
la source
120
Je ne comprends pas comment cela peut être une réponse acceptée car elle ne répond pas à la question, même si c'est un commentaire très intéressant.
qdii
14
@Mauris: Quelqu'un a édité la question et a promu une sous-question au titre de la question. Le titre original était certes horrible, mais la question de l'OP était de savoir comment fonctionne le code de piratage de bits cité, et "ce n'est pas le cas, du moins pas de manière portable, et voici pourquoi" est une réponse utile.
R .. GitHub STOP HELPING ICE
12
Ah je comprends. Malheureusement, cette question apparaît très haut dans les résultats de recherche Google pour "Qu'est-ce que c'est CHAR_BIT?" , même si ce n'était pas la question initiale. : (Compte tenu de votre explication, je comprends pourquoi vous avez écrit cette réponse, mais pour la postérité, il pourrait être plus utile soit (a) de supprimer votre réponse et de la réécrire comme un commentaire à la question, afin que @ AraK apparaisse en haut, ou (b) modifiez votre réponse afin qu'elle réponde au titre actuel de la question.
Lynn
1
En raison de la différence d'intention (s) entre la question initiale du PO et l'interprétation de celle-ci par l'éditeur, il semble que la nature de la demande originale ait été involontairement déplacée. Bien que les deux questions (originales et modifiées) aient du mérite, cette divergence doit être corrigée. Je demande maintenant: cette réponse pourrait-elle être ajoutée à un wiki? Cela pourrait aider les personnes qui recherchent ce type d'informations, même si cela ne concerne pas la question d'origine. Après cela, la question pourrait être modifiée à nouveau, pour correspondre à la demande originale de dato datuashvili. Juste un lecteur concerné ...
2
Je viens de regarder l'historique de cette question et la question originale ne demande en fait nulle part comment le code fonctionne. La question que l'éditeur a promu au titre est la seule question réelle.
plugwash
224

CHAR_BITest le nombre de bits dans char. De nos jours, presque toutes les architectures utilisent 8 bits par octet mais ce n'est pas toujours le cas. Certaines machines plus anciennes avaient un octet de 7 bits.

Il peut être trouvé dans <limits.h>.

AraK
la source
3
Certains DSP ont 10 octets ou plus.
Juri Robl
63
C nécessite CHAR_BIT>=8et autorise des valeurs beaucoup plus grandes pour les DSP qui n'ont qu'une seule taille de type, souvent 32 bits. POSIX nécessite CHAR_BIT==8. En général, vous pouvez supposer que n'importe quelle architecture orientée serveur multi-utilisateur / multitâche ou orientée utilisation interactive avec n'importe quelle chance d'être connecté à Internet ou d'échanger des données textuelles avec le monde extérieur CHAR_BIT==8.
R .. GitHub STOP HELPING ICE
6
@caf: Non, c'est que C99 nécessite les types int8_tet uint8_tpour exister. Il existe donc un type de largeur 8. Puisque sizeoftout type doit être compatible avec en sizeof charfait sizeof int8_tdoit être 1. Donc CHAR_BIT == 8. J'ai écrit quelque chose autour de cette obéservation ici: gustedt.wordpress.com/2010/06/01/how-many-bits-has-a-byte
Jens Gustedt
22
@Jens Gustedt: Veuillez citer une section dans la spécification C99. Parmi les types entiers de largeur exacte, la spécification C99 dit «Ces types sont facultatifs». (7.18.1.1/3) Les types de largeur minimale et de largeur la plus rapide sont toutefois requis.
jamesdlin
3
@jamesdlin & caf: désolé j'ai mélangé les choses. oui, l'exigence à laquelle j'ai fait référence vient en fait de POSIX pour stdint.h. Donc là, il est nécessaire, et il est également marqué comme Extension à la norme ISO C , sans faire référence à une version particulière de cette norme. Ma faute.
Jens Gustedt
2

Essayer de répondre à la fois à la question explicite (qu'est-ce que CHAR_BIT) et à la question implicite (comment cela fonctionne-t-il) dans la question d'origine.


Un caractère en C et C ++ représente la plus petite unité de mémoire que le programme C peut adresser *

CHAR_BIT en C et C ++ représente le nombre de bits dans un char. Il doit toujours être au moins égal à 8 en raison d'autres exigences du type char. En pratique, sur tous les ordinateurs à usage général modernes, il est exactement de 8, mais certains systèmes historiques ou spécialisés peuvent avoir des valeurs plus élevées.

Java n'a pas d'équivalent de CHAR_BIT ou de sizeof, il n'est pas nécessaire car tous les types primitifs en Java sont de taille fixe et la structure interne des objets est opaque pour le programmeur. Si vous traduisez ce code en Java, vous pouvez simplement remplacer "sizeof (int) * CHAR_BIT - 1" par la valeur fixe 31.

Dans ce code particulier, il est utilisé pour calculer le nombre de bits dans un int. Sachez que ce calcul suppose que le type int ne contient aucun bit de remplissage.

En supposant que votre compilateur choisisse de signer une extension sur les décalages de bits des nombres signés et en supposant que votre système utilise une représentation complémentaire de 2s pour les nombres négatifs, cela signifie que "MASK" sera 0 pour une valeur positive ou zéro et -1 pour une valeur négative.

Pour annuler un nombre de complément à deux, nous devons effectuer un non au niveau du bit, puis en ajouter un. De manière équivoque, nous pouvons en soustraire un, puis le nier au niveau du bit.

Encore une fois, en supposant que la représentation du complément à deux - -1 est représentée par tous les uns, donc exclusif ou avec -1 équivaut à une négation au niveau du bit.

Ainsi, lorsque v vaut zéro, le nombre est laissé seul, lorsque v est égal à un, il est annulé.

Il faut savoir que le débordement signé en C et C ++ est un comportement indéfini. Donc, utiliser cette implémentation ABS sur la valeur la plus négative conduit à un comportement indéfini. Cela peut être résolu en ajoutant des transtypages de sorte que la dernière ligne du programme soit évaluée dans unsigned int.

* Ce qui est généralement mais pas nécessairement la même que la plus petite unité de mémoire que le matériel peut adresser. Une mise en œuvre peut potentiellement combiner plusieurs unités de mémoire adressable par matériel en une unité de mémoire adressable par programme ou diviser une unité de mémoire adressable par matériel en plusieurs unités de mémoire adressable par programme.

plugwash
la source