C es uno de los lenguajes más utilizados en el mundo. Representa una gran proporción del código existente y continúa utilizándose para una gran cantidad de código nuevo. Es amado por sus usuarios, es tan ampliamente portado que poder ejecutar C es para muchos la definición informal de una plataforma , y sus fanáticos lo elogian por ser un lenguaje "pequeño" con un conjunto relativamente limpio de características.
Entonces, ¿dónde están todos los compiladores?
En el escritorio, hay (de manera realista) dos : GCC y Clang. Pensando en ello durante unos segundos, probablemente recordará que Intel también existe. Hay un puñado de otros, demasiado oscuros para que la persona promedio los nombre y casi universalmente no se molestan en admitir una versión de idioma reciente (o, a menudo, incluso un subconjunto de idiomas bien definido, solo "un subconjunto"). La mitad de los miembros de esta lista son notas al pie históricas; la mayoría del resto son muy especializados y aún no implementan el lenguaje completo. Muy pocos parecen ser de código abierto.
Scheme y Forth, otros idiomas pequeños que sus admiradores adoran por él, probablemente tengan más compiladores que usuarios reales. Incluso algo como SML tiene más implementaciones "serias" para elegir que C. Mientras que el anuncio de un nuevo compilador C (inacabado) que apunta a la verificación en realidad ve algunas respuestas bastante negativas, y las implementaciones veteranas luchan por conseguir suficientes contribuyentes para ponerse al día C99.
¿Por qué? ¿Es tan difícil implementar C? No es C ++. ¿Los usuarios simplemente tienen una idea muy sesgada sobre en qué grupo de complejidad se encuentra (es decir, que en realidad está más cerca de C ++ que de Scheme)?
Respuestas:
Hoy en día, necesita un compilador de C real para ser un compilador de optimización , especialmente porque C ya no es un lenguaje cercano al hardware, porque los procesadores actuales son increíblemente complejos ( fuera de orden , canalizados , superescalares , con cachés complejos y TLB , por lo tanto, necesita programación de instrucciones , etc ...). Los procesadores x86 actuales no son como los procesadores i386 del siglo anterior, incluso si ambos pueden ejecutar el mismo código de máquina. Vea que el C no es un lenguaje de bajo nivel (Su computadora no es un PDP-11 rápido) escrito por David Chisnall.
Pocas personas están utilizando compiladores de C ingenuos no optimizadores como tinycc o nwcc , ya que producen código que es varias veces más lento de lo que pueden proporcionar los compiladores de optimización.
Codificar un compilador de optimización es difícil. Observe que tanto GCC como Clang están optimizando alguna representación de código "neutral en el lenguaje fuente" (Gimple para GCC, LLVM para Clang). ¡La complejidad de un buen compilador de C no está en la fase de análisis!
En particular, hacer un compilador de C ++ no es mucho más difícil que hacer un compilador de C: analizar C ++ y transformarlo en alguna representación de código interno es complejo (porque la especificación de C ++ es compleja), pero se entiende bien, pero las partes de optimización son aún más complejo (dentro de GCC: las optimizaciones intermedias, el lenguaje de origen y el procesador de destino neutral, forman la mayoría del compilador, con el resto equilibrado entre los front-end para varios idiomas y los back-end para varios procesadores). Por lo tanto, la mayoría de los compiladores de C optimizadores también pueden compilar algunos otros lenguajes, como C ++, Fortran, D, ... Las partes específicas de C ++ de GCC son aproximadamente el 20% del compilador ...
Además, C (o C ++) se usa tanto que las personas esperan que su código sea compilable incluso cuando no sigue exactamente los estándares oficiales, que no definen con suficiente precisión la semántica del lenguaje (por lo que cada compilador puede tener su propia interpretación de eso). Mire también el compilador comprobado CompCert C y el analizador estático Frama-C , que se preocupa por una semántica más formal de C.
Y las optimizaciones son un fenómeno de cola larga : implementar algunas optimizaciones simples es fácil, ¡pero no harán que un compilador sea competitivo! Debe implementar muchas optimizaciones diferentes, y organizarlas y combinarlas inteligentemente, para obtener un compilador del mundo real que sea competitivo. En otras palabras, un compilador de optimización del mundo real tiene que ser una pieza compleja de software. Por cierto, tanto GCC como Clang / LLVM tienen varios generadores de código C / C ++ especializados internos. Y ambos son enormes bestias (varios millones de líneas de código fuente, con una tasa de crecimiento de varios por ciento cada año) con una gran comunidad de desarrolladores (unos pocos cientos de personas, que trabajan principalmente a tiempo completo, o al menos a medio tiempo).
Tenga en cuenta que no hay ningún compilador C multiproceso (que yo sepa), incluso si algunas partes de un compilador podrían ejecutarse en paralelo (por ejemplo, optimización intraprocesal, asignación de registros, programación de instrucciones ...). Y la construcción paralela con
make -j
no siempre es suficiente (especialmente con LTO ).Además, es difícil obtener fondos para codificar un compilador de C desde cero, y ese esfuerzo debe durar varios años. Finalmente, la mayoría de los compiladores de C o C ++ son software libre hoy en día (ya no hay un mercado para nuevos compiladores propietarios vendidos por startups) o al menos son productos monopólicos (como Microsoft Visual C ++ ), y es casi obligatorio ser un software gratuito para los compiladores ( porque necesitan contribuciones de muchas organizaciones diferentes).
Me encantaría obtener fondos para trabajar en un compilador de C desde cero como software libre, ¡pero no soy tan ingenuo como para creer que hoy es posible!
fuente
(there is no more a market for proprietary compilers
Dile eso al equipo de Visual Studio ...Me gustaría cuestionar su suposición subyacente de que solo hay un pequeño número de implementaciones de C.
Ni siquiera sé C, no uso C, no soy miembro de la comunidad C y, sin embargo, incluso sé mucho más que los pocos compiladores que mencionaste.
En primer lugar, está el compilador que probablemente eclipsa por completo a GCC y Clang en el escritorio: Microsoft Visual C. A pesar de las incursiones que OSX y Linux han estado haciendo en el escritorio, y la cuota de mercado que iOS y Android han "robado" lejos de los antiguos usuarios tradicionales de escritorio, Windows sigue siendo el sistema operativo de escritorio dominante, y la mayoría de los programas de escritorio de Windows C probablemente se compilan con herramientas de Microsoft.
Tradicionalmente, cada vendedor de SO y cada vendedor de chips tenían sus propios compiladores. Microsoft, como proveedor de SO, tiene Microsoft Visual C. IBM, como proveedor de SO y proveedor de chips, tiene XLC (que es el compilador predeterminado del sistema para AIX, y el compilador con el que se compilan tanto AIX como i / OS) . Intel tiene su propio compilador. Sun / Oracle tiene su propio compilador en Sun Studio.
Luego, están los proveedores de compiladores de alto rendimiento como PathScale y The Portland Group, cuyos compiladores (y bibliotecas OpenMP) se utilizan para la numeración.
Digital Mars también sigue en el negocio. Creo que Walter Bright tiene la distinción única de ser la única persona en el planeta que logró crear un compilador de C ++ con calidad de producción (principalmente) solo.
Por último, pero no menos importante, tenemos todos los compiladores patentados para microcontroladores integrados. IIRC, se venden más microcontroladores cada año que las CPU de escritorio, móviles, servidores, estaciones de trabajo y mainframe que se han vendido en toda la historia de la informática combinada. Entonces, definitivamente no son productos especializados.
Se hace una mención honorífica a TruffleC , un intérprete de C (!) Que se ejecuta en la JVM (!) Escrito usando el marco de intérprete Truffle AST que es solo un 7% más lento que GCC y Clang (lo que sea más rápido en cualquier punto de referencia particular) en todo el Computer Languages Benchmark Game, y más rápido que ambos en microbenchmarks. Usando TruffleC, el equipo de Truffle pudo obtener su versión de JRuby + Truffle para ejecutar extensiones de Ruby C más rápido que la implementación real de C Ruby.
Entonces, estas son 6 implementaciones además de las que enumeraste, que puedo nombrar en la parte superior de mi cabeza, sin siquiera saber nada sobre C.
fuente
¿Cuántos compiladores necesitas?
Si tienen diferentes conjuntos de características, crea un problema de portabilidad. Si se comercializan, elige el "predeterminado" (GCC, Clang o VS). Si le importa el último rendimiento del 5%, tiene un punto de referencia.
Si está haciendo un trabajo de lenguaje de programación de forma recreativa o con fines de investigación, es probable que sea en un lenguaje más moderno. De ahí la proliferación de compiladores de juguetes para Scheme y ML. Aunque OCaml parece estar obteniendo cierta tracción para usos no académicos y no de juguete.
Tenga en cuenta que esto varía mucho según el idioma. Java tiene esencialmente la cadena de herramientas Sun / Oracle y la GNU. Python tiene varios compiladores, ninguno de los cuales es realmente respetado en comparación con el intérprete estándar. Rust and Go tiene exactamente una implementación cada uno. C # tiene Microsoft y Mono.
fuente
1000 * 0
todavía está0
.int
, y requerirá diferentes compiladores de interpretar el mismo código fuente de maneras muy diferentes.6g
/8g
/ ... toolchain y gccgo). También solía haber una implementación comercial patentada muy interesante llamada erGo, que era a) una implementación nativa de Go de Windows en un momento en que ni gccgo ni el compilador original de Go funcionaban muy bien en Windows, b) una compañía que apostaba por Go, mucho tiempo incluso antes de que se convirtiera en 1.0, yc) la primera implementación de Go escrita en Go (gccgo y 6g / 8g están escritos en C). Sin embargo, tanto el proyecto como la compañía desaparecieron, incluso antes de que salieran de la beta cerrada.C / C ++ es único entre los lenguajes compilados, ya que tiene 3 implementaciones principales de una especificación común.
Siguiendo la regla de descartar cualquier cosa que no se use mucho, cualquier otro lenguaje compilado tiene 0 a 1.
Y creo que javascript es la única razón por la que necesita especificar 'compilado'.
fuente
uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;
como la asignación alb
valor 8192. Algunos lo definen como la asignación de 1152000000. La mayoría lo considera hoy en día como Comportamiento indefinido y es probable que almacene 3299483648, pero no promete nada al respecto.2
o2u
aparentemente./2u
? El desbordamiento sin signo está definido (como módulo 2 ^ N para N definido por la implementación) pero la división ni siquiera puede desbordarse.int
, pero cuyo producto no encajaría en ese tipo. La conversión de ese resultado a unsigned int probablemente cambiaría la interpretación del valor resultante, pero no negaría el Comportamiento Indefinido del cálculo anterior.Entonces, ¿cuál es su idioma de destino?
Los compiladores SML a menudo apuntan a C o algo así como LLVM (o como se ve en su enlace, JVM o JavaScript).
Si está compilando C, no es porque vaya a la JVM. Vas a algo peor que C. Mucho peor. Y luego puedes duplicar ese infierno menor muchas veces para todas tus plataformas de destino.
Y claro, C no es C ++, pero diría que está más cerca de C ++ que Scheme. Tiene su propio subconjunto de maldad de comportamiento indefinido (estoy mirando el tamaño de los tipos incorporados). Y si arruinas esas minucias (o lo haces "correctamente" pero inesperadamente) entonces tienes décadas de código existente en sistemas vitales que te dirá cuán terrible eres. Si arruinas un compilador SML, simplemente no funcionará, y alguien podría notarlo. Algún día.
fuente
int
tener 32 o 64 bits, pero puede ser tan pequeño como 16 bits. No es difícil en absoluto producir un número fuera del rango[−32767, +32767]
y elint
desbordamiento es UB. También haychar
/short
ser promovidoint
aounsigned int
dependiendo de siint
puede representar cada valor del tipo original, lo que puede desencadenar aún más una conversión deint
aunsigned int
si los operandos tenían diferentes tipos y se convirtieron de manera diferente, además de potencialmente otra conversión cuando asigna el resultado a una variable .