A menudo escuché a personas sugerir estudiar C. para comprender el rendimiento de la computadora, ¿es una buena idea? Estas seguro Explicaré de inmediato las conclusiones del artículo, solo por claridad absoluta:
- C no es cómo funciona la computadora.
- No creo que la mayoría de la gente hable literalmente, así que no importa.
- Comprender el contexto significa que aprender C por esta razón aún puede tener sentido, dependiendo de tus objetivos.
Planeo escribir dos artículos más con una explicación más detallada de las conclusiones, pero esto ya es suficiente. Agregue enlaces aquí cuando salgan los artículos.
A menudo escuché de la gente esto:
Al estudiar C, puedes entender cómo funcionan las computadoras.
No creo que la idea sea inicialmente incorrecta, pero tiene algunas reservas. Si los tiene en cuenta, podría ser una estrategia viable para aprender cosas nuevas e importantes. Sin embargo, rara vez veo personas discutiendo estas reservas en detalle, así que estoy escribiendo este artículo para proporcionar, en mi opinión, un contexto muy necesario ... Si está pensando en aprender C para comprender cómo funciona su computadora, entonces este artículo es para usted. Espero que ella te ayude a resolverlo.
Antes de comenzar realmente, me gustaría decir una cosa más: si quieres aprender C, ¡entonces estudia! El aprendizaje es genial. Aprender C se ha vuelto muy importante para mi comprensión de la informática y mi carrera. Aprender este lenguaje y su lugar en la historia de un lenguaje de programación te hará un mejor programador. No necesitas ninguna excusa. Aprende cosas solo por aprender. Este artículo pretende ser una guía para comprender la verdad, no discute si estudiar o no C.
En primer lugar, a quienes generalmente se recomienda esta idea. Si está tratando de "averiguar cómo funcionan las computadoras", no hace falta decir que actualmente no comprende esto. ¿Qué programadores no entienden cómo funcionan las computadoras? Básicamente, vi que este sentimiento proviene de personas que principalmente programan en lenguajes de “scripting” escritos dinámicamente como Ruby, Python o JavaScript. Supuestamente "no saben cómo funcionan las computadoras" porque estos idiomas funcionan dentro de una máquina virtual, donde solo importa la semántica de la máquina virtual. Al final, la idea de una máquina virtual es proporcionar portabilidad. El objetivo no es depender del equipo en el que se ejecuta la VM.
Solo hay un problema: C
también funciona dentro de una máquina virtual.
Abstract Machine C
De la
especificación C99 , sección 5.1.2.3, "Ejecución del programa":
Las descripciones semánticas en esta Norma Internacional describen el comportamiento de una máquina abstracta en la que los problemas de optimización no son relevantes.
En mi opinión, esto es más importante de entender cuando se aprende C. El lenguaje no "describe cómo funciona una computadora", sino que describe cómo funciona una "máquina C abstracta". Todo lo demás importante se deriva de este concepto.
Una nota más: aquí elegí C99, que no es el último estándar C. ¿Por qué? Bueno, MSVC tiene ... soporte de lenguaje C interesante , y actualmente soy usuario de Windows. Sí, puedes ejecutar clang
y gcc
en Windows. No hay una gran diferencia entre C89, C99 y C11 en cuanto a lo que estamos hablando. En algún momento, tienes que elegir. La versión que mencioné aquí incluye algunos cambios a la especificación original.
Es posible que haya escuchado otra frase en su charla en C: "C es un ensamblador portátil". Si piensa en esta frase, comprenderá que si esto es cierto, entonces C no puede corresponder al funcionamiento de una computadora: hay muchas computadoras diferentes con arquitecturas diferentes. Si C es como un ensamblador que se ejecuta en diferentes computadoras con diferentes arquitecturas, entonces no puede funcionar simultáneamente exactamente como cada una de estas computadoras.
Debe ocultar los detalles, de lo contrario no será portátil.
Sin embargo, creo que este hecho no importa, porque la gente apenas se refiere literalmente a "C es cómo funciona la computadora". Antes de volver a esto, hablemos sobre la máquina abstracta de C, y por qué muchos no parecen entender este aspecto de C.
Digresión: ¿por qué la gente se equivoca?
Solo puedo hablar de mi experiencia, aunque seguro que no es única.
Aprendí GW-BASIC, luego C, luego C ++, luego Java. Escuché sobre Java antes de comenzar a escribirlo aproximadamente en 1999, cuatro años después de su aparición. El marketing en ese momento contrastaba activamente Java y C ++, se centró en la JVM como plataforma y en el hecho de que el modelo de máquina lo distingue de C ++ y, por lo tanto, C. Sun Microsystems ya no existe, pero el
espejo del comunicado de prensa nos recuerda:
Las aplicaciones Java son independientes de la plataforma; solo necesita portar la máquina virtual Java a cada plataforma. Actúa como intérprete entre la computadora del usuario y la aplicación Java. Una aplicación escrita en el entorno Java puede funcionar en cualquier lugar, eliminando la necesidad de portar aplicaciones a múltiples plataformas.
El lema principal era "Escribe una vez, corre por todas partes". Estas dos oraciones se convirtieron en cómo yo (y muchos otros) entendimos Java, y cómo difiere de C ++. Java tiene un intérprete, una máquina virtual Java. No hay máquina virtual en C ++.
Con un marketing tan poderoso, la "máquina virtual" en la mente de muchas personas se ha convertido en sinónimo de "un gran tiempo de ejecución y / o intérprete". Los idiomas sin esta característica estaban demasiado vinculados a una computadora específica y requerían portabilidad porque no eran realmente independientes de la plataforma. La razón principal por la que Java existió fue un cambio en este defecto de C ++.
"Entorno de tiempo de ejecución", "máquina virtual" y "máquina abstracta" son palabras diferentes para el mismo concepto fundamental. Pero desde entonces han recibido diferentes connotaciones debido a una ligera variación en la implementación de estas ideas.
Personalmente, creo que este marketing de 1995 es la razón por la cual los programadores todavía no entienden la naturaleza de C.
Entonces, ¿es falsa esta afirmación? ¿Por qué Sun Microsystems gastaría millones y millones de dólares promoviendo mentiras? Si C también se basa en una máquina abstracta que ofrece portabilidad multiplataforma, ¿por qué necesitamos Java? Creo que esta es la clave para entender lo que la gente realmente quiere decir cuando dice "C es cómo funciona la computadora".
¿Qué quiere decir realmente la gente?
Aunque C funciona en el contexto de una máquina virtual, todavía es significativamente diferente de los lenguajes similares a Java. El sol no mintió. Para entender, necesitas saber la historia de C.
En 1969, Bell Labs escribió un sistema operativo de computadora en lenguaje ensamblador. En 1970, se denominó UNIX. Con el tiempo, Bell Labs compró más y más computadoras nuevas, incluida la PDP-11.
Cuando llegó el momento de portar Unix a PDP-11, decidieron usar un lenguaje de nivel superior, que era una idea bastante radical en ese momento. Imagina que hoy te diré: "Voy a escribir un sistema operativo en Java", probablemente te reirás, aunque la
idea es realizable . La situación (en mi opinión, no vivía entonces) era aproximadamente la misma. Consideramos un lenguaje llamado B, pero no admitía algunas de las funciones que tenía PDP-11 y, por lo tanto, crearon un sucesor al llamarlo "C", porque era la siguiente letra del alfabeto.
No había lenguaje "A"; B sucedió a BCPL (lenguaje de programación combinado básico).
En 1972, el primer compilador de C se escribió en PDP-11 y al mismo tiempo reescribió UNIX a C. Inicialmente, no pensaron en la portabilidad, pero C ganó fama, por lo que los compiladores de C se portaron a otros sistemas.
En 1978, se publicó la primera edición del libro "Programming Language C". Cariñosamente llamado "K&R", según los nombres de sus autores, el libro no se parecía en nada a la especificación, pero al mismo tiempo describía el lenguaje con suficiente detalle, como resultado de lo cual otros también trataron de escribir compiladores C. Más tarde, esta "versión" se llamará "K&R C".
Cuando UNIX y C se extendieron, ambos fueron portados a muchas computadoras. En los años 70 y 80, su base de hardware crecía constantemente. De la misma manera que se creó C porque B no era compatible con todas las funciones de PDP-11, muchos compiladores usaron extensiones de lenguaje. Como solo había K&R y no una especificación, esto se consideró aceptable siempre que las extensiones estuvieran bastante cerca. En 1983, la falta de estandarización estaba causando problemas, por lo que ANSI creó un equipo para preparar la especificación. En 1989, salió el estándar C89, a veces llamado "ANSI C".
La especificación C trató de unificar estas diversas implementaciones en varios hardware. Por lo tanto, la máquina C abstracta es una especie de la especificación más pequeña posible que permitiría que el mismo código funcione igual en todas las plataformas. Las implementaciones de C fueron compiladas, no interpretadas, por lo que no había intérprete, por lo tanto, no había "VM" en el sentido de 1995. Sin embargo, los programas C se escriben en esta computadora abstracta inexistente, y luego el código se convierte en ensamblador específico para la computadora particular en la que se ejecuta el programa. No puede confiar en algunos detalles específicos para escribir código portátil C. Esto hace que escribir C portátil sea muy difícil ya que puede haber hecho una suposición específica de la plataforma al escribir la versión inicial de su código.
Esto se ilustra mejor con un ejemplo. Uno de los principales tipos de datos en C es
char
, de la palabra "carácter". Sin embargo, la máquina abstracta C no determina cuántos bits deben estar en
char
. Bueno, determina, pero no por número; determina el tamaño de
CHAR_BIT
, que es una constante. Sección 5.2.4.2.1 de la especificación:
Los valores dados a continuación deben ser reemplazados por expresiones constantes adecuadas o utilizadas en las directivas de preprocesamiento #if
... Los valores en implementaciones específicas deben ser iguales o mayores en magnitud (valor absoluto) de los dados aquí con el mismo signo.
CHAR_BIT: 8
En otras palabras, sabe que
char
tiene al menos 8 bits, pero las implementaciones pueden ser mayores. Para codificar correctamente una "máquina C abstracta", debe utilizarse
CHAR_BIT
lugar de
8
como el tamaño al procesar
char
. Pero esta no es una especie de función de intérprete, ya que pensamos en máquinas virtuales; Esta es una propiedad de cómo el compilador traduce el código fuente en código de máquina.
Sí, hay sistemas donde CHAR_BIT
no CHAR_BIT
8
.
Por lo tanto, esta "máquina abstracta", aunque técnicamente es la misma idea que la máquina virtual Java, es más probable que sea una construcción de compilación para administrar compiladores al crear código ensamblador, en lugar de algún tipo de verificación o propiedad de tiempo de ejecución. El tipo equivalente en Java es un
byte
, que siempre tiene 8 bits, y la implementación de JVM tiene la tarea de qué hacer en plataformas con más bytes. (No estoy seguro si la JVM funciona en alguna de estas plataformas, pero así es como debería funcionar). La máquina abstracta C fue creada como una envoltura mínima para varios "hardware", y no como una especie de plataforma hecha de tela sólida escrita en software para su código.
Entonces, aunque Sun estaba técnicamente equivocado, en la práctica significan un poco de lo que literalmente dicen, y lo que
quieren decir es cierto. Lo mismo con la frase "Aprenda C para entender cómo funcionan las computadoras".
Aprenda C para MEJOR Entender cómo funcionan las computadoras
¿
Qué quiere decir
realmente la gente? En el contexto de "si un rubista aprende C para comprender cómo funcionan las computadoras", este es un consejo para bajar "al nivel de hierro". Es decir, no solo para comprender cómo funciona su propio programa dentro de la máquina virtual, sino también cómo funciona la combinación del programa y la VM en el contexto de la máquina misma.
Learning C
le proporcionará más de estos detalles porque la máquina abstracta está mucho más cerca del hardware y de las abstracciones de los sistemas operativos. El lenguaje C es muy diferente de los lenguajes de alto nivel, por lo que aprenderlo puede enseñar mucho.
Pero es importante recordar que C es esencialmente una
abstracción de hardware, y las abstracciones son imperfectas. Tenga cuidado con lo que hace C o cómo funciona con la máquina misma. Si profundiza demasiado, seguramente encontrará estas diferencias, que pueden causar problemas. La mayoría de los recursos de capacitación para C, especialmente hoy en día, cuando el equipo se está volviendo más homogéneo, promoverá la idea de que
así es como funciona una computadora. Por lo tanto, puede ser difícil para un estudiante comprender lo que sucede debajo del capó y cuál es la abstracción proporcionada por C.
En esta discusión, ni siquiera tocamos otros temas. Por ejemplo, debido a la enorme popularidad de C, el hardware se ha vuelto más uniforme porque tiende a moverse hacia la semántica de la máquina abstracta C. Si su arquitectura es muy diferente de la semántica C, los programas C pueden funcionar mucho más lentamente que otros. y la velocidad del hardware a menudo se mide mediante pruebas en C. Este artículo ya es bastante largo ...
Por esta razón, creo que una versión más precisa de esta declaración sería "Al aprender C, aprenderá
más sobre cómo funcionan las computadoras". Realmente creo que un conocimiento aproximado de C es útil para muchos programadores, incluso si ellos mismos no escriben C. La introducción de C también le dará una idea de la historia de nuestra industria.
Hay otras formas de explorar este tema; Inherentemente, C no está diseñado para aprender sobre una computadora, pero es una buena opción.
Hay mucho que aprender en programación. Les deseo éxito en este viaje.