J'ai vu la ligne de code suivante ici en C.
int mask = ~0;
J'ai imprimé la valeur de mask
en C et C++. Il imprime toujours -1
.
J'ai donc quelques questions:
~0
à la variable du masque ?~0
?-1
au lieu de ~0
?C'est une façon portable de définir tous les bits binaires d'un entier sur 1 bit sans avoir à savoir combien de bits sont dans l'entier sur l'architecture actuelle.
C et C++ autorisent 3 formats entiers signés différents: amplitude du signe, complément à un et complément à deux
~0
produira des bits tout-en-un quel que soit le format de signe que le système utilise. C'est donc plus portable que -1
Vous pouvez ajouter le suffixe U
(c'est-à-dire -1U
) pour générer un modèle de bits tout-en-un portable1. Toutefois ~0
indique l'intention plus claire : inverser tous les bits dans la valeur 0 alors que -1 montrera qu'une valeur de moins un est nécessaire, pas son binaire représentation
1 parce que les opérations non signées sont toujours modulo réduit le nombre qui est un supérieur à la plus grande valeur qui peut être représentée par le type résultant
Que sur une plate-forme complémentaire de 2 (c'est supposé) vous donne -1, mais écrire -1 directement est interdit par les règles (seulement les entiers 0..255, unaire !
, ~
et binaire &
, ^
, |
, +
, <<
et >>
sont autorisés).
Vous étudiez un défi de codage avec un certain nombre de restrictions sur les opérateurs et les constructions de langage pour effectuer des tâches données.
Le premier problème est retourne la valeur -1 sans utiliser le -
opérateur.
Sur les machines qui représentent des nombres négatifs avec un complément à deux, la valeur -1
est représenté avec tous les bits définis sur 1
, alors ~0
correspond à -1
:
/*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
// ~0 = 111...111 = -1
return ~0;
}
D'autres problèmes dans le fichier ne sont pas toujours implémentés correctement. Le deuxième problème, renvoyer une valeur booléenne représentant le fait qu'une valeur int
rentrerait dans un _ 16 $ signé short
a un défaut:
/*
* fitsShort - return 1 if x can be represented as a
* 16-bit, two's complement integer.
* Examples: fitsShort(33000) = 0, fitsShort(-32768) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int fitsShort(int x) {
/*
* after left shift 16 and right shift 16, the left 16 of x is 00000..00 or 111...1111
* so after shift, if x remains the same, then it means that x can be represent as 16-bit
*/
return !(((x << 16) >> 16) ^ x);
}
Le décalage vers la gauche d'une valeur négative ou d'un nombre dont la valeur décalée dépasse la plage de int
a un comportement indéfini, le décalage vers la droite d'une valeur négative est défini par l'implémentation, de sorte que la solution ci-dessus est incorrecte (bien que ce soit probablement la solution attendue) .
Il y a longtemps, c'est ainsi que vous avez économisé de la mémoire sur des équipements extrêmement limités tels que l'ordinateur 1K ZX 80 ou ZX 81. En BASIC, vous
Let X = NOT PI
plutôt que
LET X = 0
Étant donné que les nombres étaient stockés sous forme de virgules flottantes de 4 octets, ce dernier prend 2 octets de plus que la première alternative NOT PI, où chacun de NOT et PI prend un seul octet.
Il existe plusieurs façons de coder les nombres dans toutes les architectures informatiques. Lorsque vous utilisez le complément de 2, cela sera toujours vrai: ~0 == -1
. D'un autre côté, certains ordinateurs utilisent le complément de 1 pour coder les nombres négatifs pour lesquels l'exemple ci-dessus est faux, car ~0 == -0
. Oui, le complément 1 a un zéro négatif, et c'est pourquoi il n'est pas très intuitif.
Donc à vos questions
mask & sth == sth
Ma pensée personnelle - rendez votre code aussi indépendant de la plateforme que possible. Le coût est relativement faible et le code devient infaillible