Perché ci sono così pochi compilatori C?


72

C è una delle lingue più utilizzate al mondo. Rappresenta un'enorme percentuale del codice esistente e continua ad essere utilizzato per una grande quantità di nuovo codice. È amato dai suoi utenti, è così ampiamente portato che essere in grado di eseguire C è per molti la definizione informale di una piattaforma ed è elogiato dai suoi fan per essere un "piccolo" linguaggio con un set relativamente pulito di funzionalità.

Quindi dove sono tutti i compilatori?

Sul desktop, ce ne sono (realisticamente) due : GCC e Clang. Pensandoci per qualche secondo probabilmente ti ricorderai che esiste anche Intel. Ce ne sono una manciata di altri, troppo oscuri per essere nominati dalla persona media e quasi universalmente non si preoccupano di supportare una versione linguistica recente (o spesso anche un sottoinsieme di lingue ben definito, solo "un sottoinsieme"). La metà dei membri di questo elenco sono note storiche; la maggior parte degli altri è molto specializzata e non implementa ancora il linguaggio completo. Pochissimi in realtà sembrano essere open-source.

Scheme and Forth - altre piccole lingue che sono amate dai loro fan per questo - probabilmente hanno più compilatori rispetto agli utenti reali. Anche qualcosa come SML ha implementazioni più "serie" tra cui scegliere rispetto a C. Considerando che l'annuncio di un nuovo compilatore C (incompiuto) che mira alla verifica in realtà vede alcune risposte piuttosto negative, e le implementazioni veterane fanno fatica a ottenere abbastanza collaboratori da raggiungere C99.

Perché? L'implementazione di C è così difficile? Non è C ++. Gli utenti hanno semplicemente un'idea molto distorta di quale gruppo di complessità rientra (ovvero che in realtà è più vicino al C ++ rispetto allo Schema)?


61
MSVC conta ancora, almeno come compilatore C89. Probabilmente anche più popolare di Intel.
Rufflewind,

22
Wikipedia elenca alcuni compilatori C. Diventano molto comuni quando ti trovi nel regno incorporato.

113
di quanti compilatori hai bisogno per compilare il tuo codice C?
Bryan Chen,

76
La domanda si basa su una premessa errata. Analog Devices, armcc, il compilatore C di Bruce, il compilatore incrociato Bare-C, il compilatore Borland, il compilatore clang, il compilatore Cosmic C, il compilatore CodeWarrior, il compilatore dokto, il compilatore Ericsson, e non sono nemmeno fuori dal prime cinque lettere dell'alfabeto ancora. C'è un numero follemente grande di compilatori C. La domanda è "perché ci sono così pochi compilatori C, se non contiamo queste diverse dozzine come veri compilatori C?" Hai definito la stragrande maggioranza dei compilatori C come non interessante, motivo per cui non ce ne sono molti.
Eric Lippert,

19
"Perché" le domande sono cattive domande per questo sito nel migliore dei casi, e "perché no?" le domande sono peggiori. Se dovessi incontrarti a una festa e chiedermi "allora, perché non registri barche a vela?" Penso che avresti giustamente trovato una domanda strana. Non è necessario fornire una giustificazione per NON impegnarsi in un hobby tecnicamente difficile, fisicamente rischioso e molto costoso. Scrivere qualsiasi software non banale è costoso, difficile e rischioso e quindi richiede un enorme motivatore. Una domanda migliore sarebbe "perché ci sono così tanti compilatori C?" È sorprendente che ce ne sia più di uno.
Eric Lippert,

Risposte:


153

Oggi, è necessario un vero compilatore C per essere un compilatore ottimizzante , in particolare perché C non è più un linguaggio vicino all'hardware, poiché i processori attuali sono incredibilmente complessi ( fuori servizio , pipeline , superscalari , con cache complesse e TLB , quindi necessita di programmazione delle istruzioni , ecc ...). I processori x86 di oggi non sono come i processori i386 del secolo precedente, anche se entrambi sono in grado di eseguire lo stesso codice macchina. Vedi che la C non è un linguaggio di basso livello (Il tuo computer non è un PDP-11 veloce) di David Chisnall.

Poche persone usano ingenui compilatori C non ottimizzanti come tinycc o nwcc , poiché producono codice che è molte volte più lento di quello che l'ottimizzazione dei compilatori può dare.

Codificare un compilatore ottimizzante è difficile. Si noti che sia GCC che Clang stanno ottimizzando alcune rappresentazioni di codice "neutre dal linguaggio di origine" (Gimple per GCC, LLVM per Clang). La complessità di un buon compilatore C non è nella fase di analisi!

In particolare, la creazione di un compilatore C ++ non è molto più difficile della creazione di un compilatore C: l'analisi del C ++ e la sua trasformazione in una rappresentazione del codice interno è complessa (perché la specifica C ++ è complessa), ma è ben compresa, ma le parti di ottimizzazione sono ancora di più complesso (all'interno di GCC: le ottimizzazioni di fascia media, neutre nella lingua di origine e nel processore di destinazione, formano la maggior parte del compilatore, con il resto bilanciato tra front-end per diverse lingue e back-end per diversi processori). Quindi la maggior parte dei compilatori C ottimizzanti sono anche in grado di compilare alcuni altri linguaggi, come C ++, Fortran, D, ... Le parti specifiche di C ++ di GCC sono circa il 20% del compilatore ...

Inoltre, C (o C ++) è così ampiamente usato che le persone si aspettano che il loro codice sia compilabile anche quando non segue esattamente gli standard ufficiali, che non definiscono abbastanza precisamente la semantica del linguaggio (quindi ogni compilatore può avere una propria interpretazione di esso). Guarda anche il compiler C comprovato CompCert e l' analizzatore statico Frama-C , che si preoccupano della semantica più formale di C.

E le ottimizzazioni sono un fenomeno long tail : implementare alcune semplici ottimizzazioni è facile, ma non renderanno competitivo un compilatore! È necessario implementare molte ottimizzazioni diverse e organizzarle e combinarle in modo intelligente per ottenere un compilatore del mondo reale competitivo. In altre parole, un compilatore per l'ottimizzazione del mondo reale deve essere un software complesso. A proposito, sia GCC che Clang / LLVM hanno diversi generatori di codice interni C / C ++ specializzati. Ed entrambi sono bestie enormi (diversi milioni di righe di codice sorgente, con un tasso di crescita di diversi percento ogni anno) con una grande comunità di sviluppatori (poche centinaia di persone, che lavorano principalmente a tempo pieno o almeno a metà tempo).

Si noti che non esiste un compilatore C multi-thread (per quanto ne so), anche se alcune parti di un compilatore potrebbero essere eseguite in parallelo (ad es. Ottimizzazione intra-procedurale, allocazione dei registri, pianificazione delle istruzioni ...). E la costruzione parallela con make -jnon è sempre abbastanza (specialmente con LTO ).

Inoltre, è difficile ottenere finanziamenti per la codifica di un compilatore C da zero, e tale sforzo deve durare diversi anni. Infine, oggi la maggior parte dei compilatori C o C ++ sono software gratuiti (non esiste più un mercato per i nuovi compilatori proprietari venduti dalle startup) o almeno sono prodotti monopolistici (come Microsoft Visual C ++ ), ed è quasi necessario essere un software gratuito per i compilatori ( perché hanno bisogno di contributi da molte organizzazioni diverse).

Sarei felice di ottenere finanziamenti per lavorare da zero su un compilatore C come software libero, ma non sono abbastanza ingenuo da credere che sia possibile oggi!


14
(there is no more a market for proprietary compilersDillo al team di Visual Studio ...
Mason Wheeler,

18
Microsoft ha il monopolio. Intendevo dire che le piccole aziende che sviluppano nuovi compilatori C non ne venderanno molti. Puoi nominare un recente concorrente proprietario di MSVC?
Basile Starynkevitch,

12
Esistono molti compilatori proprietari nel mondo HPC. PGCC, NAG e ICC sono i più utilizzati.
Davidmh,

37
@MasonWheeler: VS è dato gratuitamente oggi (come nella birra). Le versioni non libere aggiungono strumenti, ma il compilatore C in VS2013 è lo stesso in tutte le versioni. Semplicemente non c'è un mercato, nemmeno per loro.
Salterio del

3
Ma sia GCC che LLVM stanno operando su rappresentazioni molto più basse e ottimizzano allo stesso modo il codice C ++ & C (& Ada & Fortran, per GCC). Direi al contrario che C ++ richiede più ottimizzazione (in particolare durante la compilazione del codice usando il suo STL) di C!
Basile Starynkevitch,

70

Vorrei contestare la vostra ipotesi di base che ci sono solo un numero limitato di implementazioni in C.

Non conosco nemmeno C, non uso C, non sono un membro della comunità C, eppure conosco molto di più dei pochi compilatori che hai citato.

Innanzitutto, c'è il compilatore che probabilmente ridimensiona completamente sia GCC che Clang sul desktop: Microsoft Visual C. Nonostante gli ostacoli che OSX e Linux hanno fatto sul desktop, e la condivisione di mercato che iOS e Android hanno "rubato" lontano dagli ex utenti desktop tradizionali, Windows è ancora il sistema operativo desktop dominante e la maggior parte dei programmi desktop C di Windows è probabilmente compilata utilizzando strumenti Microsoft.

Tradizionalmente, ogni fornitore di sistemi operativi e ogni fornitore di chip aveva i propri compilatori. Microsoft, come fornitore del sistema operativo, dispone di Microsoft Visual C. IBM, sia come fornitore del sistema operativo sia come fornitore di chip, ha XLC (che è il compilatore di sistema predefinito per AIX e il compilatore con cui vengono compilati sia AIX che i / OS) . Intel ha il proprio compilatore. Sun / Oracle hanno il proprio compilatore in Sun Studio.

Quindi, ci sono i fornitori di compilatori ad alte prestazioni come PathScale e The Portland Group, i cui compilatori (e librerie OpenMP) vengono utilizzati per lo scricchiolio dei numeri.

Anche Digital Mars è ancora in attività. Credo che Walter Bright abbia l'eccezionale distinzione di essere l'unica persona al mondo che è riuscita a creare da solo un compilatore C ++ di qualità di produzione.

Ultimo ma non meno importante, abbiamo tutti i compilatori proprietari per microcontrollori incorporati. IIRC, ogni anno vengono venduti più microcontrollori rispetto a CPU desktop, mobili, server, workstation e mainframe vendute nell'intera storia dell'informatica combinata. Quindi, questi sono sicuramente non prodotti di nicchia.

Una menzione d'onore va a TruffleC , un interprete C (!) In esecuzione su JVM (!) Scritto usando il framework di interpreti Truffle AST che è solo il 7% più lento di GCC e Clang (qualunque sia il più veloce su qualsiasi dato benchmark) in tutto il Computer Language Benchmark Game, e più veloce di entrambi sui microbenchmark. Utilizzando TruffleC, il team Truffle è stato in grado di ottenere la propria versione di JRuby + Truffle per eseguire le estensioni di Ruby C più velocemente dell'attuale implementazione di C Ruby!

Quindi, queste sono 6 implementazioni in aggiunta a quelle che hai elencato che posso nominare in cima alla mia testa, senza nemmeno sapere nulla di C.


1
Al di fuori di Microsoft Visual C, la maggior parte dei compilatori C citati viene utilizzata raramente.
Basile Starynkevitch,

6
MSVC è il grande compilatore C ++, ma per C è difficile da usare e permanentemente bloccato in C89; i compilatori di microcontrollori sono generalmente specifici per target, bloccati in C89 e stravaganti; TruffleC non sembra essere ancora disponibile (ma è interessante, grazie). Pathscale e Digital Mars sembrano più simili al tipo di controesempi che stavo cercando però.
Leushenko,

8
@Mario il mio significato non è che C89 è rotto, ma C89 non è la forma aggiornata della lingua; e ciò significa che esistono meno compilatori aggiornati .
Leushenko,

6
@Leushenko MSVC non è permanentemente bloccato in C89. Ci sono state alcune discussioni e si dovrebbero aggiungere altre funzionalità C99. Per cominciare, la maggior parte della libreria C99 è supportata a partire da MSVC 2015 e anche alcune funzionalità linguistiche (principalmente le cose necessarie per C ++ 11).
Morwenn,

5
@Morwenn: la politica di Microsoft sembra essere che C99 non risolva alcun problema che C ++ non aveva già risolto e che se stai programmando il sistema dovresti usare il sottoinsieme C-like di C ++ (tutto ciò che non richiede il runtime o in cui non è possibile controllare la posizione in cui verrà inserito il compilatore, importante se è necessario assicurarsi che il codice o i dati non vengano inviati agli stati in cui il paging è disabilitato). Le uniche funzionalità di C99 saranno le cose richieste nelle specifiche C ++ successive e quelle che non sono pensate per essere implementate.
Mike Dimmick,

8

Di quanti compilatori hai bisogno?

Se hanno diversi set di funzionalità, si crea un problema di portabilità. Se sono mercificati, scegli "default" (GCC, Clang o VS). Se ti interessa l'ultima performance del 5%, hai un benchmark-off.

Se stai facendo un lavoro di linguaggio di programmazione per scopi ricreativi o per scopi di ricerca, è probabile che sia in un linguaggio più moderno. Da qui la proliferazione di compilatori di giocattoli per Scheme e ML. Sebbene OCaml stia ottenendo una certa trazione per usi non accademici non giocattolo.

Nota che questo varia molto in base alla lingua. Java ha essenzialmente la toolchain Sun / Oracle e quella GNU. Python ha vari compilatori nessuno dei quali è veramente rispettato rispetto all'interprete standard. Rust e Go hanno esattamente un'implementazione ciascuno. C # ha Microsoft e Mono.


1
È ovvio che ci sono ragioni più interessanti per sviluppare un compilatore ML ... Pensavo solo che la comunità C essendo probabilmente tre ordini di grandezza più grandi avrebbe bilanciato quell'effetto. Ma potresti avere ragione, 1000 * 0è ancora 0.
Leushenko,

La creazione di un nuovo compilatore è spesso collegata alla frammentazione della comunità (causata o causata). Ad esempio, la divisione del manutentore egcs vs gcc. Inoltre, la compatibilità della sorgente C tende a essere inferiore al 100%.
pjc50,

@ pjc50: il modo in cui lo standard è scritto suddivide efficacemente C in un numero di dialetti disgiunti basati su cose come il tipo base di int, e richiederà diversi compilatori per interpretare lo stesso codice sorgente in modi molto diversi.
supercat,

5
Credo, Go ha due implementazioni (il 6g/ 8g/ ... toolchain e gccgo). C'era anche un'implementazione commerciale proprietaria molto interessante chiamata erGo, che era a) un'implementazione nativa di Windows di Go in un momento in cui né gccgo né il compilatore Go originale funzionavano molto bene su Windows, b) un'azienda che scommetteva su Go, a lungo prima ancora che diventasse 1.0 ec) la prima implementazione di Go scritta in Go (gccgo e 6g / 8g sono entrambi scritti in C). Sia il progetto che la compagnia svanirono, tuttavia, prima ancora di uscire dalla closed beta.
Jörg W Mittag,

6

C / C ++ è unico tra i linguaggi compilati in quanto ha 3 importanti implementazioni di una specifica comune.

Seguendo la regola di respingere tutto ciò che non è molto usato, ogni altra lingua compilata ha 0 a 1.

E penso che JavaScript sia l'unico motivo per cui devi specificare "compilato".


2
L'etichetta "C" è applicata a un numero di lingue diverse; alcuni definiscono il codice uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;come assegnazione al bvalore 8192. Alcuni lo definiscono come assegnazione di 1152000000. La maggior parte oggigiorno lo considera un comportamento indefinito e probabilmente memorizzerà 3299483648 ma non promette in tal senso.
supercat,

1
@supercat: Ah, una buona strana con overflow e regole di promozione dei numeri interi. Si basa sull'uso 2o 2uapparentemente.
Zan Lynx,

1
@ZanLynx: non credo che ci siano casi in cui 2 contro 2u sia legittimamente importante; l'unico caso che conosco dove potrebbe interessare riguarda il comportamento indefinito con 2 e 2u.
supercat,

3
@supercat: come otterresti un comportamento indefinito /2u? L'overflow senza segno è definito (come modulo 2 ^ N per N definito dall'implementazione) ma la divisione non può nemmeno overflow.
MSalters,

2
Il comportamento indefinito verrebbe dalla moltiplicazione dei valori che verrebbero promossi a firmati int, ma il cui prodotto non si adatterebbe a quel tipo. La forzatura di quel risultato a un int senza segno cambierebbe probabilmente l'interpretazione del valore risultante, ma non annullerebbe il comportamento indefinito dal calcolo precedente.
supercat,

5

Qual è la tua lingua di destinazione?

I compilatori SML hanno spesso come target C o qualcosa di simile a LLVM (o come si vede nel tuo link, JVM o JavaScript).

Se stai compilando C, non è perché stai andando alla JVM. Stai andando a qualcosa di peggio di C. Molto peggio. E poi puoi duplicare quel piccolo inferno un sacco di volte per tutte le tue piattaforme target.

E certo, C non è C ++, ma direi che è più vicino a C ++ che a Scheme. Ha un suo sottoinsieme di malvagità comportamentale indefinita (sto osservando le dimensioni dei tipi incorporati). E se rovini quelle minuzie (o lo fai "correttamente" ma inaspettatamente) allora hai decenni di codice esistente su sistemi vitali che ti diranno quanto sei terribile. Se rovini un compilatore SML, semplicemente non funzionerà e qualcuno potrebbe accorgersene. Un giorno.


SML / NJ e PolyML sono entrambi compilati per codice macchina ...
Basile Starynkevitch

2
In che modo int size "Undefined Behaviour"? E perché UB sarebbe comunque un peso per i venditori di compilatori? L'unico vero onere per gli autori di compilatori è che le larghezze int sono definite dall'implementazione, non non specificate, quindi devi documentare ciò che hai fatto.
MSalters,

@MSalters In realtà, gli autori di compilatori per una piattaforma consolidata hanno l'onere di abbinare ciò che altri hanno fatto prima di loro. A volte questo è documentato e standardizzato, a volte no. È facile trovare la dimensione di un int, ma è più difficile trovare ciò che viene fatto con i valori di registro e dove vengono archiviati gli argomenti quando si chiama una funzione (che può cambiare a seconda dei tipi di argomento e del tipo di ritorno della funzione), regole di layout della struttura, ecc.
Casuale 832,

@MSalters La maggior parte delle persone si aspetta intche siano 32 o 64 bit, ma può essere piccola come 16 bit. Non è affatto difficile produrre un numero al di fuori dell'intervallo [−32767, +32767]e l' intoverflow è UB. C'è anche char/ shortottenere promosso a int o unsigned int seconda che intpuò rappresentare tutti i valori del tipo di originale, che può innescare ulteriormente una conversione da inta unsigned intse gli operandi hanno avuto diversi tipi e si sono convertite in modo diverso, più potenzialmente un'altra conversione quando si assegna il risultato a una variabile .
Doval,

@MSalters C'è abbastanza margine nella dimensione dei tipi standard e abbastanza conversioni implicite che scommetto che per quasi tutti i programmi C non banali c'è una scelta di numeri interi legali che gli faranno fare la cosa sbagliata o causare una definizione indefinita comportamento.
Doval,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.