TL; DR
C heredó los operadores !
y ~
de otro idioma. Ambos &&
y ||
fueron agregados años después por una persona diferente.
Respuesta larga
Históricamente, C se desarrolló a partir de los primeros idiomas B, que se basaba en BCPL, que se basaba en CPL, que se basaba en Algol.
Algol , el bisabuelo de C ++, Java y C #, definió verdadero y falso de una manera intuitiva para los programadores: "valores de verdad que, considerados como un número binario (verdadero correspondiente a 1 y falso a 0), es lo mismo que el valor integral intrínseco ". Sin embargo, una desventaja de esto es que la lógica y el bit a bit no pueden ser la misma operación: en cualquier computadora moderna, ~0
es igual a -1 en lugar de 1 e ~1
igual a -2 en lugar de 0. (Incluso en un mainframe de sesenta años donde ~0
representa - 0 o INT_MIN
, ~0 != 1
en cada CPU que se haya fabricado, y el estándar del lenguaje C lo ha requerido durante muchos años, mientras que la mayoría de sus lenguajes secundarios ni siquiera se molestan en admitir el signo y la magnitud o el complemento de uno.
Algol resolvió esto al tener diferentes modos e interpretar operadores de manera diferente en modo booleano e integral. Es decir, una operación bit a bit era una en tipos enteros, y una operación lógica era una en tipos booleanos.
BCPL tenía un tipo booleano separado, pero un solo not
operador , tanto para bit a bit como lógico. La forma en que este precursor temprano de C hizo ese trabajo fue:
El Rvalue de verdadero es un patrón de bits completamente compuesto de unos; El valor de falso es cero.
Tenga en cuenta que true = ~ false
(Observará que el término rvalue ha evolucionado para significar algo completamente diferente en los lenguajes de la familia C. Hoy lo llamaríamos "la representación del objeto" en C.)
Esta definición permitiría lógica y bit a bit no utilizar la misma instrucción en lenguaje máquina. Si C hubiera seguido esa ruta, los archivos de encabezado en todo el mundo dirían #define TRUE -1
.
Pero el lenguaje de programación B era de tipo débil y no tenía tipos booleanos o incluso de coma flotante. Todo era equivalente int
en su sucesor, C. Esto hizo que fuera una buena idea que el lenguaje definiera lo que sucedía cuando un programa usaba un valor distinto de verdadero o falso como valor lógico. Primero definió una expresión verdadera como "no es igual a cero". Esto fue eficiente en las minicomputadoras en las que se ejecutaba, que tenían un indicador de CPU cero.
En ese momento, había una alternativa: las mismas CPU también tenían un indicador negativo y el valor de verdad de BCPL era -1, por lo que B podría haber definido todos los números negativos como verdaderos y todos los números no negativos como falsos. (Hay un remanente de este enfoque: UNIX, desarrollado por las mismas personas al mismo tiempo, define todos los códigos de error como enteros negativos. Muchas de sus llamadas al sistema devuelven uno de varios valores negativos diferentes en caso de falla). Así que esté agradecido: ¡podría haber sido peor!
Pero definir TRUE
as 1
y FALSE
as 0
en B significaba que la identidad true = ~ false
ya no se mantenía, y había dejado caer el tipo fuerte que permitía a Algol desambiguar entre expresiones bit a bit y lógicas. Eso requería un nuevo operador lógico, y los diseñadores eligieron !
, posiblemente porque ya no era igual a !=
, que se parece a una barra vertical a través de un signo igual. No siguieron la misma convención como &&
o ||
porque ninguno de los dos existía.
Podría decirse que deberían tener: el &
operador en B está roto como se diseñó. En B y en C, 1 & 2 == FALSE
a pesar de que 1
y 2
son ambos valores Truthy, y no hay manera intuitiva para expresar la operación lógica en B. Eso fue un error C trató de rectificar en parte mediante la adición &&
y ||
, pero la principal preocupación en ese momento era de finalmente ponga en cortocircuito al trabajo y haga que los programas se ejecuten más rápido. La prueba de esto es que no existe ^^
: 1 ^ 2
es un valor verdadero a pesar de que ambos operandos son verdaderos, pero no puede beneficiarse del cortocircuito.