Domanda

Perché non è possibile scrivere un compilatore che gestisce ciò che deve essere gestito nel codice C ++ (cioè per renderlo " CLR compatibile ")?

Forse con qualche compromesso, come vietare i puntatori void in alcune situazioni, ecc. Ma tutte queste parole chiave extra ecc. Qual è il problema che deve essere risolto da queste aggiunte?

Ho i miei pensieri su alcuni aspetti e ciò che potrebbe essere difficile da risolvere, ma una buona spiegazione solida sarebbe molto apprezzata!

È stato utile?

Soluzione

Finora non sarei in disaccordo con le risposte.

Il problema principale da capire è che un compilatore C ++ crea codice adatto a un ambiente molto stupido. Anche una CPU moderna non conosce le funzioni virtuali, l'inferno, anche le funzioni sono un tratto. Ad una CPU davvero non importa che il codice di gestione delle eccezioni per srotolare lo stack esca da qualsiasi funzione, per esempio. Affare della CPU in sequenze di istruzioni, con salti e ritorni. Le funzioni certamente non hanno nomi per quanto riguarda la CPU.

Quindi, tutto il necessario per supportare il concetto di funzione viene messo lì dal compilatore. Per esempio. vtables sono solo array della giusta dimensione, con i giusti valori dal punto di vista della CPU. __func__ finisce come una sequenza di byte nella tabella delle stringhe, l'ultima delle quali è 00.

Ora, non c'è nulla che dica che l'ambiente di destinazione deve essere stupido . Potresti sicuramente scegliere come target JVM. Ancora una volta, il compilatore deve compilare ciò che non viene offerto in modo nativo. Nessuna memoria non elaborata? Quindi allocare un array di byte di grandi dimensioni e utilizzarlo invece. Nessun puntatore non elaborato? Usa solo gli indici interi in quel grande array di byte.

Il problema principale è che il programma C ++ sembra piuttosto irriconoscibile dall'ambiente di hosting. La JVM non è stupida, conosce le funzioni, ma si aspetta che siano membri della classe. Non si aspetta che abbiano < e > nel loro nome. Puoi aggirare questo, ma quello che finisci con è fondamentalmente la menomazione del nome. E a differenza della modifica del nome oggi, questo tipo di modifica del nome non è inteso per i linker C ma per ambienti intelligenti. Quindi, il suo motore di riflessione potrebbe convincersi che esiste una classe c__plus__plus con la funzione membro __namespace_std__for_each__arguments_int_pointer_int_pointer_function_address , e questo è ancora un buon esempio. Non voglio sapere cosa succede se hai un std :: map di stringhe per invertire gli iteratori.

Il contrario è in realtà molto più semplice, in generale. Praticamente tutte le astrazioni di altre lingue possono essere massaggiate via in C ++. Raccolta dei rifiuti? Questo è già consentito in C ++ oggi, quindi potresti supportarlo anche per void * .

Una cosa che non ho ancora affrontato è la prestazione. Emulazione della memoria raw in un array di byte di grandi dimensioni? Non sarà veloce, soprattutto se ci metti il ??doppio. Puoi giocare molti trucchi per renderlo più veloce, ma a quale prezzo? Probabilmente non otterrai un prodotto commercialmente valido. In effetti, potresti avere un linguaggio che combina le parti peggiori di C ++ (molti comportamenti insoliti dipendenti dall'implementazione) con le parti peggiori di una VM (lenta).

Altri suggerimenti

Il codice corretto esistente, ovvero il codice scritto secondo lo standard C ++, non deve modificarlo inavvertitamente.

Bene, C ++ / CLI è principalmente pensato per essere una colla tra codice gestito e non gestito. Come tale è necessario avere la capacità di mescolare concetti gestiti e non gestiti. Devi essere in grado di allocare oggetti gestiti e non combinati nello stesso codice, quindi non c'è modo di aggirare parole chiave separate.

Perché non è possibile compilare il codice C ++ nativo destinato al CLR?

Sì, hai indovinato bene, ci sarebbero troppi compromessi, che lo renderebbero inutile. Vorrei citare solo tre esempi ...

1.) Modelli: C ++ li supporta, il CLR no (i generici sono diversi). Quindi non è possibile utilizzare STL, boost ecc. Nel proprio codice.

2.) Eredità multipla: supportata in C ++, non in CLI. Non puoi nemmeno usare la classe e le derivate iostream standard (come stringstream, fstream), che ereditano sia da istream che da ostream.

Quasi nessuno dei codici là fuori sarebbe compilato, non si poteva nemmeno implementare la libreria standard.

3.) Garbage collection: La maggior parte delle app C ++ gestisce la propria memoria manualmente (usando i puntatori intelligenti ecc.), Il CLR ha una gestione automatica della memoria. Pertanto, lo stile C ++ "nuovo" e " elimina " sarebbe incompatibile con " gcnew " ;, rendendo inutile il codice C ++ esistente per questo nuovo compilatore.

Se dovessi sradicare tutte le funzionalità importanti, anche la libreria standard, e non verrà compilato alcun codice esistente ... qual è il punto?

Prima di tutto, la distinzione tra "semplice C ++" e "gestito C ++" era intenzionale, perché uno degli scopi di MC ++ era quello di fornire un ponte tra il codice C ++ esistente e CLR.

Successivamente, ci sono troppe funzionalità C ++ che non rientrano nel modello CLR. Eredità multipla, modelli, aritmetica dei puntatori ... Senza tracciare una linea chiara, i programmatori sarebbero condannati ad affrontare errori criptici, sia in fase di compilazione che di runtime.

Penso che ciò sia dovuto al fatto che l'aggiunta di funzionalità di codice gestito in C ++ renderebbe C ++ più lento e il compilatore più complesso. Tanto che C ++ perderebbe ciò per cui è stato progettato in primo luogo. Una delle cose carine di C ++ è che è un bel linguaggio con cui lavorare, è abbastanza basso livello e tuttavia un po 'portatile. E probabilmente questo è ciò che il Comitato Standard C ++ intende far sì che rimanga tale. Ad ogni modo, non credo che il C ++ possa mai essere completamente "gestito", poiché ciò significherebbe che i programmi scritti in C ++ necessitano di una VM per essere eseguiti. In tal caso, perché non usare semplicemente C ++ / CLI?

Qt framework fa quasi questo. Cioè ha puntatori intelligenti, che vengono automaticamente impostati su null, quando l'oggetto a cui puntano viene distrutto. E ancora è un C ++ nativo, dopo aver analizzato moc (compilatore di meta oggetti).

Sì, suppongo che C ++ potrebbe essere gestito. Ma poi .NET dovrebbe essere riscritto per C ++ e non con un orientamento verso BASIC. Con molte lingue tutte sotto lo stesso tetto. Alcune funzioni devono andare. È stata una scelta tra VB.NET o C ++. NET, ed è stato scelto VB.NET. La cosa divertente che sento è che C # è più popolare di VB.NET (anche se non uso nessuno dei due!).

Il CLR .NET richiede che non possa mai esistere alcun riferimento a un oggetto gestito ovunque il runtime non sia a conoscenza tranne quando l'oggetto è bloccato; una buona prestazione richiede che gli oggetti siano bloccati il ??meno possibile. Poiché .NET CLR non è in grado di comprendere tutte le strutture di dati utilizzabili in C ++, è indispensabile che in tali strutture non vengano mai mantenuti riferimenti a oggetti gestiti. Sarebbe possibile avere "ordinario" Il codice C ++ interagisce con il codice .NET senza alcuna modifica al linguaggio C ++, ma l'unico modo in cui il codice C ++ può mantenere qualsiasi tipo di "riferimento" a qualsiasi oggetto .NET sarebbe avere un codice sul lato .NET assegnare a ciascun oggetto un handle di qualche tipo e mantenere una tabella statica degli oggetti associati agli handle. Il codice C ++ che voleva manipolare gli oggetti dovrebbe quindi chiedere al wrapper .NET di eseguire alcune operazioni sull'oggetto identificato da un handle. L'aggiunta della nuova sintassi consente al compilatore di identificare i tipi di oggetti che il framework .NET dovrà conoscere e applicare le restrizioni necessarie su di essi.

la prima cosa da considerare è ogni cosa che rende c ++ " veloce " scomparirà. un sistema di garbage collection completo in c ++ è quasi impossibile. perché c ++ puoi avere il puntatore quasi ovunque nel codice. le informazioni sul tipo di runtime diventano costose se non integrate direttamente in sistema di lingua stessa. puoi trarre vantaggio dalle prestazioni native reali. il modello scompare. i veri puntatori spariranno. l'accesso diretto alla memoria è sparito.

elenco di cose che dovrebbero essere applicate

1. no direct pointers(pointers will get replace with complex refernces)
2. templates (generics pay for preformance)
3. simple c-style arrays (will get wrapped with array structures)
4. programmer no longer has control of whether data is on the stack or
the heap.
5. garbage collection will be enforced(this will cause the most changes to the syntax)
6. runtime type data will get added extensively to the code.
(larger code size)
7.  inlining will become more difficult for the compiler
(no more inline key word)
8. no more inline assembly.
9. the new langauge by now will become incompatible c code.(unless you go through hoops) 

Sono d'accordo con 5hammer! Se ho lasciato Java e altre lingue gestite non è per niente: questo è avere il controllo COMPLETO sul computer, accedere alla memoria gestire la memoria da solo, avere il controllo su come il computer eseguirà il mio codice, integrarsi con le librerie C (come Lua). Se perdo questa flessibilità, lascerei semplicemente C ++ e ritornerei a C, e se anche C diventasse gestito, andrei all'assemblatore.

Le lingue gestite sono le peggiori di sempre per tutte le piattaforme di gioco / programmi complessi in quanto ti legano in qualche kine di sandbox senza accesso diretto all'hardware e sono molto più lente delle lingue compilate.

Lo scopo principale di C ++ era sempre stato Performence. È una delle lingue migliori per i grandi giochi. E senza queste prestazioni linguistiche non esisterebbero molti giochi!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top