2010-03-11 17 views
31

Me di cuenta de que puede simplemente #define algunos enteros, pero ¿por qué C no tenía un tipo de datos booleano dedicado antes de C99?¿Por qué C no tiene un tipo de datos booleano anterior a C99?

Es una ocurrencia tan común en la programación y la lógica, que no entiendo la ausencia de un tipo explícito y notación.

+5

-1: ¿Qué problema se resuelve conociendo la historia de los detalles de implementación de C de Kernighan y Ritchie? –

+38

@ S.Lott - lo siento, ¿no entendí el propósito de StackOverflow? ¿Esta pregunta no está relacionada con la programación? De las preguntas frecuentes: "este es un lugar para preguntas que pueden ser respondidas". "Siempre y cuando su pregunta sea ... detallada y específica, escrita de manera clara y simple, de interés para al menos otro programador en alguna parte". ¿Qué más extrañé? –

+19

@ S.Lott sospecho que debe eliminar el capítulo "Antecedentes e Historia" de su libro de Python. –

Respuesta

24

Si pasa un poco de tiempo en la biblioteca, no tiene que especular. Aquí hay algunas declaraciones tomadas de Dennis Ritchie's paper on the evolution of C. El contexto es que Dennis está construyendo sobre el lenguaje B de Ken Thompson, que se implementó en el minúsculo PDP-7, una máquina con palabra escrita. Debido al creciente interés, el grupo obtuvo uno de los primeros PDP-11. Dennis escribe,

La llegada del PDP-11 expuso varias deficiencias del modelo semántico de B. Primero, sus mecanismos de manejo de caracteres, heredados con pocos cambios de BCPL, eran torpes: el uso de procedimientos de biblioteca para separar cadenas empaquetadas en celdas individuales y luego reempaquetar, o para acceder y reemplazar caracteres individuales, comenzó a parecer incómodo, incluso tonto, en una máquina orientada a bytes.

El modelo B y BCPL implica una sobrecarga en el manejo de punteros: las reglas del lenguaje, al definir un puntero como un índice en una matriz de palabras, los punteros forzados se representan como índices de palabras. Cada referencia de puntero generaba una conversión de escala de tiempo de ejecución desde el puntero a la dirección de bytes que esperaba el hardware.

Por todas estas razones, parecía que era necesario un esquema de tipado para manejar el direccionamiento de caracteres y bytes, y para prepararse para el próximo hardware de coma flotante. Otros problemas, en particular la seguridad de tipo y la comprobación de interfaz, no parecían tan importantes como lo fueron después.

(El subrayado es mío.)

El papel pasa a describir las luchas de Dennis inventar una nueva semántica puntero, para hacer arreglos de trabajo, y para llegar a un acuerdo con esta idea novedosos struct. Las nociones de tipo seguridad y distinguir booleanos de enteros no parecían importantes hasta mucho más tarde :-)

1

Porque no pusieron uno. Lo siento si suena raro, pero básicamente no se definió como tal.

Recuerde que la mayoría de la gente #define VERDADERO y FALSO.

Puede decir que bool ES estándar, pero obviamente NO ERA estándar antes de C99, que se fabricó hace 10 años;) Lo agregaron cuando se hizo evidente que faltaba un artículo.

+3

que acabas de parafrasearlo: P –

+5

+1: "Porque no pusieron uno". La única respuesta posible. –

+0

Es estándar no solo en programación sino también en el proceso de pensamiento cuando se resuelve un problema. – xyz

0

Porque ninguno puede prever todo, incluido el tipo de datos faltante en un lenguaje de programación.

17

C es en realidad poco más que un lenguaje ensamblador de nivel superior. Sí, tiene estructuras de control y todo eso e incluso tiene tipos que el ensamblador ciertamente no necesita.

Pero el lenguaje fue diseñado hace décadas. Y dado que cada resultado booleano se reduce a bits individuales en la palabra de estado del procesador, obviamente fue suficiente con solo usar un tipo de datos integral para él. Y hizo el compilador probablemente un poco menos complejo ya que puede omitir alguna verificación de tipo (en las versiones posteriores las estructuras de control necesitan un valor booleano, en C solo necesitan un valor integral de 0 o algo más).

+11

Recuerde que el principio C también usó 'char *' antes de que 'void *' se estandarizara como el tipo de puntero genérico. Un procesador no tenía noción de 'vacío', por lo que el lenguaje usaba el puntero de datos de resolución más pequeña que el hardware entendía. Más nociones "abstractas" como 'void *' vinieron después. C es un lenguaje muy cercano al metal, y el resumen de verdadero/falso en un nuevo tipo de datos que no refleja algo que el hardware puede entender de manera única no tiene mucho sentido (un 'bool' sería simplemente un' char' con limitaciones adicionales, lo suficientemente simple para 'typedef' si realmente lo necesita). – bta

7

Sospecho que se consideró suficiente tener un tipo entero, 0 es falso y nada 0 verdadero.

+1

Creo que esta es la mejor respuesta. La mayoría de los booleanos se manejan como enteros de todos modos cuando se compilan para assember. –

9

Una CPU no tiene "tipo booleano", solo trabajan en bytes y múltiplos de ellos, por lo que un tipo booleano no tenía sentido en ese momento ya que no daba una ventaja (¿por qué usar un tipo cuando solo se puede verificar? "es 0" o "no es nulo")

+2

Claro que la CPU tiene tipos booleanos. ¡El registro de banderas está lleno de ellos! – xtofl

+1

Sí, pero no son de propósito general. – dbemerlin

10

Era común (y aún lo es en algunos casos) tratar cero como falso y cualquier valor distinto de cero como verdadero. Esto tiene ventajas para la taquigrafía: por ejemplo, en lugar de while (remaining != 0), puede usar while (remaining).

Algunos idiomas estandarizados en el ser verdadero -1. La razón para esto es que en la notación de dos complementos (que la mayoría de las computadoras usan para representar números negativos), bitwise-not de 0 es -1 (en 8-bit binary, 11111111 es decimal -1).

Con el tiempo, se ha constatado que el uso de una constante definida por el compilador evitaría una gran confusión potencial. Ha pasado un tiempo desde que hice C++, pero estoy bastante seguro de que cualquier valor distinto de cero evaluará "verdadero".

+0

+1 por ser la respuesta más detallada –

+2

Siempre encontré el 0/-1 algo interesante cuando lo descubrí por primera vez, especialmente dado que muchos docentes/profesores explicaban incorrectamente que el positivo 1 era "verdadero". –

+4

Positivo 1 ** es ** "verdadero" en C, en el sentido de que los operadores de comparación y operadores booleanos y/o no evalúan a 1 o 0 para verdadero o falso, respectivamente. Pero es mejor no pensar que cierto tiene un valor, ya que cualquier valor distinto de cero es verdadero. –

5

El tipo que utiliza para almacenar un booleano (por lo general) representa una solución de compromiso entre el espacio y el tiempo. Por lo general, obtendrá los resultados más rápidos (al menos para una operación individual) utilizando un int (generalmente cuatro bytes). Por otro lado, si está usando muchas, puede tener mucho más sentido usar un byte o incluso empaquetarlas para que cada valor que esté almacenando solo use un solo bit, pero cuando/si lo hace, leer o escribir un solo bit se vuelve sustancialmente más caro.

Dado que no había una sola respuesta que fuera realmente "correcta", dejaron la decisión al usuario de hacer en función de los requisitos del programa que estaban escribiendo.

La verdadera pregunta, entonces, es por qué se agregó un tipo booleano en C99.Creo que hay un par de factores involucrados. En primer lugar, se dieron cuenta de que la conveniencia para el programador ahora es más importante que ofrecer el mejor rendimiento posible. En segundo lugar, los compiladores ahora hacen un análisis bastante más global, por lo que es posible adivinar que alguien podría escribir un compilador que intenta elegir una representación que sea más apropiada para un programa en particular (aunque no conozco ninguna que realmente lo hace).

+0

+1: Me gustó la mención de espacio-tiempo-intercambio. Ese es un punto muy importante. – Arun

+0

En algunos compiladores, un 'int' es el formato más rápido para almacenar un valor booleano. En muchos (pero no en todos), sin embargo, un 'char' sería igual de rápido. Algunos procesadores de sistemas integrados tienen un tipo especial de "bit" que es aún más rápido (aunque tales procesadores generalmente no permiten incluir tipos de "bit" dentro de otras estructuras). Sería una tontería almacenar un booleano en un 'int' en una plataforma donde un' char' sería igual de rápido (o, para algunos procesadores integrados, incluso más rápido). – supercat

+0

Lo que dijo el supercat, también, el objetivo inicial para c era generalmente máquinas con memoria muy limitada, casi siempre preferiría administrar su empaque de bit manualmente. Agregar un tipo booleano en ese momento habría alentado lo que entonces se habría considerado una salida de código de máquina terrible. –

4

razones históricas, probablemente:

CPL, que fue fuertemente influenciado por Algol, muy probablemente tenían un tipo booleano, pero mi google-fu no son suficientes para encontrar una referencia para esto. Pero CPL era demasiado ambicioso para su tiempo, lo que resultó en una versión simplificada llamada BCPL, que tenía el beneficio de que realmente podría implementarlo en el hardware disponible.

BCPL sólo tenía un solo tipo - la 'palabra' - que fue interpretado como falsa en contextos booleanas si 0 y tan cierto si ~0 (es decir, el complemento de 0, lo que representaría el valor -1 si se interpreta como twos- firmado complemento entero). La interpretación de cualquier otro valor dependía de la implementación.

Después del sucesor aún sin letra B, C reintrodujo un sistema de tipo, pero todavía estaba muy influenciado por la naturaleza sin sistema de sus predecesores.

5

La antigua C no era realmente "faltante" de un tipo booleano, era solo que todos los tipos integrales también se consideraban adecuados para haciendo doblemente deber, almacenando booleanos.Veo dos razones principales para esto:

  • procesadores de bits de direccionamiento no eran en absoluto común (y aún no lo son), por lo que el compilador no sería realmente capaz de utilizar un "verdadero booleano" escriba para guardar cualquier espacio: el valor booleano aún sería al menos tan grande como char de todos modos (si esperaba acceder de manera eficiente).

  • Tipos más estrechos que int se ensanchan a int en las expresiones de todos modos - por lo que los operadores booleanos todavía funcionaría en int operandos.

... así que parece que no había un caso lo suficientemente convincente como para que un tipo booleano dedicado realmente transmitiera beneficios prácticos.

Recuerde que el lenguaje C tiene un conjunto de operadores que producen resultados booleanos (definido a ser 0 o 1) - !, &&, ||, !=, ==, <, <=, > y >= - por lo que es un tipo booleano dedicado que no está allí.

1

Agregar un tipo "booleano" separado que no sea compatible con enteros habría complicado el compilador más que el simple uso de enteros para tal fin. Tener un tipo booleano diferente que sea compatible con enteros hace necesario especificar las posibles consecuencias de almacenar un valor distinto de 0 o 1 en un objeto booleano, o realizar cálculos numéricos en un objeto booleano cuya representación no contiene ni el patrón de bits asociado con "0" ni "1". Teniendo en cuenta:

someBool = intFunction(); 
someInt = someBool; 

exigir que someInt debe recibir el valor 1 si intFunction devuelve cualquier valor distinto de cero sería en general que el anterior más caro que

someChar = intFunction(); 
someInt = someChar; 

En los casos en que se requeriría que el ex semántica, que podrían cumplirse sin el uso de un tipo booleano, a través de:

someChar = !!intFunction(); 
someInt = someChar; 

ya que cualquier cosa que se pueda hacer uso de tipos de Boole también se puede hacer sin ellos, y en muchos casos c La oda que usa tipos de caracteres puede ser más eficiente que los tipos booleanos, sugiero que nunca hubo (y todavía no existe) ninguna necesidad real de ellos.

Cuestiones relacionadas