Las respuestas anteriores dan más o menos la explicación, aunque principalmente desde un ángulo pragmático, por mucho que la pregunta tenga sentido , como lo explica excelentemente la respuesta de Raphael .
Además de esta respuesta, debemos tener en cuenta que, hoy en día, los compiladores de C están escritos en C. Por supuesto, como señaló Raphael, su salida y su rendimiento pueden depender, entre otras cosas, de la CPU en la que se está ejecutando. Pero también depende de la cantidad de optimización realizada por el compilador. Si escribe en C un mejor compilador de optimización para C (que luego compila con el anterior para poder ejecutarlo), obtendrá un nuevo compilador que hace que C sea un lenguaje más rápido que antes. Entonces, ¿cuál es la velocidad de C? Tenga en cuenta que incluso puede compilar el nuevo compilador consigo mismo, como un segundo paso, de modo que se compila de manera más eficiente, aunque sigue dando el mismo código de objeto. Y el teorema del pleno empleo muestra que no hay fin a tales mejoras (gracias a Rafael por el puntero).
Pero creo que puede valer la pena tratar de formalizar el problema, ya que ilustra muy bien algunos conceptos fundamentales, y particularmente la visión denotacional versus operativa de las cosas.
¿Qué es un compilador?
Un compilador , abreviado a si no hay ambigüedad, es la realización de una función computable que traducirá un texto de programa computando una función , escrito en un lenguaje fuente en el texto del programa escrito en un
idioma de destino , que se supone que para calcular la misma función .CS→TCCS→TP:SP SP:T TP
Desde un punto de vista semántico, es decir, denotacionalmente , no importa cómo se calcula esta función de compilación , es decir, qué realización se elige . Incluso podría hacerse por un oráculo mágico. Matemáticamente, la función es simplemente un conjunto de pares .CS→TCS→T{(P:S,P:T)∣PS∈S∧PT∈T}
La función de recopilación semántica es correcta si ambos y calculan la misma función . Pero esta formalización se aplica también a un compilador incorrecto. El único punto es que todo lo que se implementa logra el mismo resultado independientemente de los medios de implementación. Lo que importa semánticamente es lo que hace el compilador, no cómo (y qué tan rápido) se hace.CS→TPSPTP
En realidad, obtener de es un problema operativo que debe resolverse. Esta es la razón por la cual la función de compilación debe ser una función computable. Entonces, cualquier idioma con el poder de Turing, sin importar cuán lento sea, seguramente podrá producir código tan eficiente como cualquier otro idioma, incluso si lo hace de manera menos eficiente.P:TP:SCS→T
Refinando el argumento, probablemente queremos que el compilador tenga una buena eficiencia, de modo que la traducción se pueda realizar en un tiempo razonable. Por lo tanto, el rendimiento del programa compilador es importante para los usuarios, pero no tiene ningún impacto en la semántica. Estoy diciendo rendimiento, porque la complejidad teórica de algunos compiladores puede ser mucho mayor de lo que cabría esperar.
Sobre bootstrapping
Esto ilustrará la distinción y mostrará una aplicación práctica.
Ahora es un lugar común implementar primero un lenguaje con un intérprete , y luego escribir un compilador en el lenguaje mismo. Este compilador se puede ejecutar con el intérprete para traducir cualquier programa en un programa . Así que tenemos un compilador en ejecución desde el lenguaje al lenguaje (¿máquina?) , pero es muy lento, aunque solo sea porque se ejecuta sobre un intérprete.I S C S → TSIS S C S → TCS→T:SS I S P : S P : T STCS→T:SISP:SP:TST
Pero puede usar esta función de compilación para compilar el compilador
, ya que está escrito en el lenguaje , y así obtiene un compilador escrito en el idioma de destino . Si se supone, como suele ser el caso, de que es un lenguaje que se interpreta de manera más eficiente (nativo de la máquina, por ejemplo), entonces se obtiene una versión más rápida de su compilador se ejecuta directamente en el lenguaje . Realiza exactamente el mismo trabajo (es decir, produce los mismos programas de destino), pero lo hace de manera más eficiente. S C S → TCS→T:SS TTTCS→T:TTTT