En utilisant des opérateurs au niveau du bit pour les Booléens en C++
Est-il une raison de ne pas utiliser les opérateurs au niveau du bit &, | et ^ pour "bool" valeurs en C++?
J'ai parfois dans des situations où je veux exactement l'une des deux conditions pour être vrai (XOR), donc je viens de lancer le ^ opérateur dans une expression conditionnelle. J'ai aussi parfois besoin de toutes les pièces d'une condition à évaluer si le résultat est vrai ou pas (plutôt que de court-circuit), j'ai donc utiliser & et |. J'ai aussi besoin d'accumuler des valeurs Booléennes parfois, et &= et |= peut être très utile.
J'ai eu un peu soulevé les sourcils quand le faire, mais le code est toujours significatif et plus propre qu'il en serait autrement. Est-il une raison de ne PAS les utiliser pour booléens? Sont là tout les compilateurs modernes qui donnent de mauvais résultats pour cette?
- Si vous avez appris suffisamment bien le C++ depuis posant cette question, vous devez revenir et de l'onu-d'accepter la réponse actuelle et accepter Patrick Johnmeyer de réponse pour en expliquant correctement le court-circuit de la différence.
- Remarque générale parce que les gens en question si c'est une bonne idée. Si vous vous souciez de la direction générale de la couverture des tests unitaires, puis la réduction des branches est souhaitable. Les opérateurs sur les bits sont utiles pour cela.
Vous devez vous connecter pour publier un commentaire.
||
et&&
sont des opérateurs booléens et le haut-sont garantis pour renvoyer latrue
oufalse
. Rien d'autre.|
,&
et^
sont des opérateurs au niveau du bit. Lorsque le domaine de numéros de fonctionnement sur est que de 1 et de 0, alors qu'ils sont exactement les mêmes, mais dans les cas où votre booléens ne sont pas strictement des 1 et des 0 – comme c'est le cas avec le langage C – vous pouvez vous retrouver avec un comportement que vous ne vouliez pas. Par exemple:En C++, cependant, la
bool
type est garanti d'être seulement untrue
ou unfalse
(qui convertir implicitement respectivement1
et0
), il est donc moins de souci à partir de cette position, mais le fait que les gens ne sont pas habitués à voir de telles choses dans le code qui fait un bon argument pour ne pas le faire. Juste direb = b && x
et être fait avec elle.bool passed_tests_ = true; passed_tests_ &= 8;
, ce qui signifie que l'un de mes tests est fragile pour les éditer plus tard... (recherche pour c'est ce qui m'a amené ici)Deux raisons principales. En bref, l'examiner attentivement; il pourrait y avoir une bonne raison pour cela, mais si il est TRÈS explicite dans vos commentaires, car il peut être fragile et, comme vous le dites vous-même, les gens ne sont généralement pas l'habitude de voir ce type de code.
Xor au niveau du bit != Logique xor (sauf pour les 0 et 1)
Tout d'abord, si vous êtes d'exploitation sur d'autres valeurs que
false
ettrue
(ou0
et1
, comme les entiers), les^
opérateur peut introduire comportement n'équivaut pas à une logique xor. Par exemple:De crédit de l'utilisateur @Patrick pour exprimer cette première.
Ordre des opérations
Deuxième,
|
,&
, et^
, que les opérateurs au niveau du bit, ne pas faire de court-circuit. En outre, plusieurs opérateurs au niveau du bit enchaînés dans un seul énoncé, même avec des parenthèses explicites, peuvent être réorganisées par l'optimisation des compilateurs, parce que tous les 3 opérations sont normalement commutative. Ceci est important si l'ordre des opérations de questions.En d'autres termes
ne sera pas toujours donner le même résultat (ou à la fin de l'état) comme
Ceci est particulièrement important parce que vous ne pouvez pas les méthodes de contrôle de
a()
etb()
, ou quelqu'un d'autre peut venir le long et les modifier par la suite de ne pas comprendre la dépendance, et de provoquer un méchant (et souvent de presse-construire uniquement) bug.Je pense que
est ce que vous voulez
!==
façon de parler) donc, si vous êtes le calcul de la XOR d'une séquence debool
valeurs que vous devez écrireacc = acc!= condition(i);
dans un corps de boucle. Le compilateur pouvez probablement gérer cela de manière aussi efficace que si!==
existé, mais certains pourraient trouver qu'il n'a pas l'air gentil, et préfèrent l'option d'ajouter des booléens comme des entiers, puis de tester si la somme est impaire.Les sourcils haussés devrait vous en dire assez pour arrêter de le faire. Vous n'avez pas à écrire le code pour le compilateur, vous l'écrire pour vos collègues programmeurs d'abord et ensuite pour le compilateur. Même si les compilateurs de travail, surprenante, les autres personnes n'est pas ce que vous voulez - opérateurs au niveau du bit sont pour les opérations sur les bits non pour les booléens.
Je suppose que vous aussi manger des pommes avec une fourchette? Cela fonctionne, mais il surprend donc c'est mieux de ne pas le faire.
Les inconvénients de la bitlevel opérateurs.
Vous demander:
Oui, le opérateurs logiques, c'est le haut-niveau élevé d'opérateurs booléens
!
,&&
et||
, offrent les avantages suivants:Garanti conversion des arguments à
bool
, c'est à dire à0
et1
valeur ordinale.Garanti de court-circuit de l'évaluation où l'évaluation de l'expression s'arrête dès que le résultat final est connu.
Cela peut être interprété comme un arbre-valeur logique, avec Vrai, Faux et Indéterminée.
Lisible des équivalents textuels
not
,and
etor
, même si je n'utilise pas moi-même.En tant que lecteur de l'Antimoine notes dans un commentaire aussi la bitlevel les opérateurs n'ont pas d'autres jetons, à savoir
bitand
,bitor
,xor
etcompl
, mais à mon avis, ce sont moins lisible queand
,or
etnot
.Il suffit de mettre, chaque parti du niveau élevé des opérateurs est un inconvénient de la bitlevel opérateurs.
En particulier, depuis les opérateurs au niveau du bit manque d'argument conversion 0/1 vous obtenez par exemple
1 & 2
→0
, tandis que1 && 2
→true
. Aussi^
, bit à bit ou exclusif, peut mal se conduire de cette façon. Considérés comme des valeurs booléennes 1 et 2 sont les mêmes, à savoirtrue
, mais considéré comme bitpatterns ils sont différents.Comment exprimer la logique soit/ou en C++.
Ensuite, vous fournissez un peu de fond de la question,
Bien, les opérateurs au niveau du bit ont priorité plus élevée que les opérateurs logiques. Cela signifie en particulier que, dans un mixte d'expression tels que des
vous obtenez le résultat inattendu peut-être
a && (b ^ c)
.Au lieu d'écrire simplement
exprimant de façon plus concise ce que vous voulez dire.
Pour les multiples argument soit/ou il n'y a pas de C++ opérateur qui fait le travail. Par exemple, si vous écrivez
a ^ b ^ c
que ce n'est pas une expression qui dit que “soita
,b
ouc
est vrai“. Au lieu de cela il dit, “Un nombre impair dea
,b
etc
sont vraies“, qui pourrait être 1 d'entre eux ou tous les 3...Pour exprimer le général soit/ou quand
a
,b
etc
sont de typebool
, il suffit d'écrireou, avec les non-
bool
arguments, de les convertir enbool
:À l'aide de
&=
à s'accumuler boolean résultats.Vous élaborer davantage,
Bien, cela correspond à vérifier si respectivement tous ou tout condition est satisfaite, et de Morgan, la loi de vous indique comment passer de l'un à l'autre. I. e. vous avez seulement besoin de l'un d'eux. Vous pouvez en principe utiliser
*=
comme un&&=
-opérateur (pour que ce bon vieux George Boole découvert, logique ET peut très facilement être exprimé comme une multiplication), mais je pense que ce serait perplexe et peut-être induire en erreur les responsables de la maintenance de code.Considérer aussi:
Sortie avec Visual C++ 11.0 et g++ 4.7.1:
La raison de la différence dans les résultats est que le bitlevel
&=
ne fournit pas une conversion àbool
de sa main droite à côté de l'argument.Oui, laquelle de ces résultats avez-vous le désir de votre utilisation de
&=
?Si l'ancienne,
true
, puis de mieux définir un opérateur (par exemple, comme ci-dessus) ou le nom de la fonction, ou l'utilisation d'une conversion explicite de la main droite à côté de l'expression, ou d'écriture de la mise à jour complète.bitand
,bitor
,xor
etcompl
. Je pense que c'est pourquoi j'ai utilisé la qualification "lisible". Bien sûr, la lisibilité, par exemple, decompl 42
est subjective. 😉bool
" est simplement une conséquence de la convention, ne garantit pas que le langage C++ donne réellement de vous.+
garantit la conversion de ses arguments pourunsigned
, mais cela n'empêche pasunsigned int n=-1; n+=3.14;
de l'utilisation de l'double
(ou est-cefloat
?) opération d'addition. (Comparer votre&=
exemple.)Contrairement à Patrick de réponse, C++ n'a pas de
^^
opérateur pour la réalisation d'un court-circuit ou exclusif. Si vous pensez à ce sujet pendant une seconde, ayant un^^
opérateur n'aurait pas de sens de toute façon: avec ou exclusif, le résultat dépend toujours de deux opérandes. Cependant, Patrick avertissement au sujet de la non-bool
"Boolean" types détient aussi bien lorsque l'on compare les1 & 2
à1 && 2
. Un exemple classique est le WindowsGetMessage()
la fonction, qui renvoie un tri-stateBOOL
: non nulle,0
, ou-1
.À l'aide de
&
au lieu de&&
et|
au lieu de||
n'est pas rare qu'une faute de frappe, donc si vous êtes délibérément de le faire, il mérite un commentaire en expliquant pourquoi.^^
opérateur de encore être utile quel que soit le court-circuit de l'examen. Il est: a) évaluer les opérandes dans un contexte booléen et b) de garantir le retour d'un 1 ou 0.inline bool XOR(bool a,bool b) { return a!=b; }
et obtenir ce que vous voulez, sauf que c'est une fonction plutôt qu'une (infixe) de l'opérateur. Ou vous pouvez directement utiliser!=
ou la surcharge de certains autre opérateur avec ce sens, mais alors bien sûr, vous devez être très prudent pour ne pas finir accidentellement à l'aide involontaire de surcharge du même nom. Et d'ailleurs||
et&&
retourtrue
oufalse
, pas1
ou0
.!
,||
et&&
évaluer leurs arguments dans un contexte Booléen est seulement parce que ces opérateurs sont rarement surchargé d'accepter d'autres types; pour autant que je peux dire que la langue ne permettent de telles surcharges, et, par conséquent, ne garantit pas l'évaluation des arguments dans un contexte Booléen.Patrick a fait de bons points, et je ne vais pas les répéter. Cependant pourrais-je vous suggérer la réduction des "si", des déclarations lisible en anglais dans la mesure du possible en utilisant le bien-nommé boolean vars.Par exemple, et c'est à l'aide des opérateurs booléens mais vous pouvez également les utiliser au niveau du bit et le nom de la booléens de façon appropriée:
Vous pourriez penser qu'à l'aide d'un booléen semble inutile, mais cela permet deux choses principales:
EDIT: Vous navez pas explicitement dit que vous vouliez les conditions de 'si' consolidés (bien que cela semble le plus probable), qui a été mon hypothèse. Mais ma suggestion d'un intermédiaire valeur booléenne est toujours debout.
IIRC, de nombreux compilateurs C++ pour les avertir lors de la tentative de jeter le résultat d'une opération au niveau du bit comme un booléen. Vous devez utiliser un type de cast pour faire le bonheur du compilateur.
À l'aide d'une opération au niveau du bit dans une expression if permettrait d'atteindre le même critique, mais peut-être pas par le compilateur. Toute valeur non nulle est considérée comme vraie, donc quelque chose comme "si (7 & 3)" sera vrai. Ce comportement peut être acceptable en Perl, mais le C/C++ sont très explicites langues. Je pense que le Spock sourcil est due diligence. 🙂 Je voudrais ajouter "== 0" ou "!= 0" pour le rendre parfaitement claire de ce que votre objectif est.
Mais de toute façon, ça sonne comme une question de préférence personnelle. Je voudrais exécuter le code, grâce à charpie ou un outil similaire et voir si elle pense aussi que c'est pas une bonne stratégie. Personnellement, il se lit comme une erreur de codage.
À l'aide des opérations bit à bit pour le type bool permet d'économiser inutile direction de la prédiction de la logique par le processeur, résultant d'une 'cmp' enseignement apporté par des opérations logiques.
Remplacement de la logique avec des opérations bit à bit (où tous les opérandes sont bool) génère un code plus efficace en offrant le même résultat. L'efficacité dans l'idéal, devrait l'emporter sur tous les courts-circuit avantages que peut être un effet de levier de la commande à l'aide des opérations logiques.
Cela peut rendre le code un peu non-lisible mais le programmeur doit commenter les raisons pour lesquelles il a été fait.