TL; DR
C a hérité des opérateurs !
and ~
d’une autre langue. Les deux &&
et ||
ont été ajoutés des années plus tard par une personne différente.
Longue réponse
Historiquement, C s'est développé à partir des premières langues B, qui étaient basées sur BCPL, qui était basé sur CPL, qui était basé sur Algol.
Algol , l'arrière-petit-père de C ++, Java et C #, a défini vrai et faux de manière intuitive pour les programmeurs: «valeurs de vérité qui, considérées comme un nombre binaire (vrai correspondant à 1 et faux à 0), sont identique à la valeur intrinsèque intrinsèque ». Cependant, un inconvénient de cela est que logique et que bit à bit ne peut pas être la même opération: sur tout ordinateur moderne, ~0
égal à -1 plutôt que 1 et ~1
égal à -2 plutôt que 0 (même sur un ordinateur central vieux de soixante ans où ~0
représente - 0 ou INT_MIN
, ~0 != 1
sur chaque processeur jamais créé, et la norme de langage C l’exige depuis de nombreuses années, alors que la plupart des langues de sa fille ne se soucient même pas de prendre en charge le principe de complémentarité.
Algol a contourné cela en ayant différents modes et en interprétant les opérateurs différemment en mode booléen et intégral. C'est-à-dire qu'une opération au niveau des bits était une opération sur les types entiers et une opération logique, une opération sur des types booléens.
BCPL avait un type booléen distinct, mais un seul not
opérateur , à la fois au niveau du bit et logique. La manière dont ce précurseur précoce de C a réalisé ce travail était:
La valeur de true est un modèle de bits entièrement composé de uns; la Rvalue de false est zéro.
Notez que true = ~ false
(Vous remarquerez que le terme rvalue a évolué pour signifier quelque chose de complètement différent dans les langues de la famille C. Nous appellerions aujourd'hui cela «la représentation d'objet» en C).
Cette définition permettrait à logique et au bit de ne pas utiliser la même instruction en langage machine. Si C avait choisi cette voie, diraient les fichiers d’en-tête du monde entier #define TRUE -1
.
Mais le langage de programmation B était faiblement typé et n'avait pas de type booléen ni même de type virgule flottante. Tout était l'équivalent de int
son successeur, C. Cela incitait le langage à définir ce qui se passait lorsqu'un programme utilisait une valeur autre que true ou false comme valeur logique. Il a d'abord défini une expression de vérité comme étant «non égale à zéro». Cette méthode était efficace sur les mini-ordinateurs sur lesquels il fonctionnait, qui présentaient un indicateur de zéro CPU.
Il y avait à l'époque une alternative: les mêmes processeurs avaient également un drapeau négatif et la valeur de vérité de BCPL était -1, alors B aurait peut-être défini tous les nombres négatifs comme des vrais et tous les nombres non négatifs comme des faux. (Il y a un reste de cette approche: UNIX, développé par les mêmes personnes en même temps, définit tous les codes d'erreur en tant qu'entiers négatifs. Beaucoup de ses appels système renvoient l'une de plusieurs valeurs négatives différentes en cas d'échec.) Soyez donc reconnaissant: il Aurait pu être pire!
Mais définir TRUE
comme 1
et FALSE
comme 0
dans B signifiait que l’identité true = ~ false
n’était plus conservée et que le typage fort qui permettait à Algol de ne pas être ambiguïté entre les expressions binaires et logiques disparaissait. Cela nécessitait un nouvel opérateur logique-non, et les concepteurs ont choisi !
, peut-être parce que non-égal-à était déjà !=
, qui ressemble à une barre verticale à travers un signe égal. Ils n'ont pas suivi la même convention &&
ou ||
parce que ni l'un ni l'autre n'existaient encore.
On peut soutenir qu'ils devraient avoir: l' &
opérateur en B est cassé comme prévu. En B et en C, 1 & 2 == FALSE
même si 1
et 2
sont deux valeurs véridiques, et il n’existe aucun moyen intuitif d’exprimer l’opération logique en B. C’est une erreur que C a tenté de rectifier en partie en ajoutant &&
et ||
, mais la principale préoccupation à l’époque était de: enfin, faites fonctionner les courts-circuits et accélérez les programmes. La preuve est qu'il n'y a pas ^^
: 1 ^ 2
est une valeur truthy même si ses deux opérandes sont truthy, mais il ne peut pas bénéficier de court-circuit.