Compilazione, interpretazione e funzionamento della CPU
Ho dei dubbi sul funzionamento delle due cose. QUando ho un programma in C++ ad esempio, io compilo, poi cosa succede? Viene generato un file assembly, che l' assemblatore traduce in linguaggio macchina binario pronto per essere eseguito dalla CPU? Se ho un linguaggio interpretato invece, il computer esegue un interprete, che a sua volta legge e converte ad una ad una le istruzioni e le esegue? Quindi il programma vero e proprio non è eseguito dal pc, ma esso esegue l' interprete che è quello che esegue in realtà il programma usando una sua memoria e le sue strutture dati? Per esempio si dice che Java sia semiinterpretato perchè noi compiliamo, viene generato un file eseguibile dalla java virtual machine, quindi il pc esegue la virtual machine che a sua volta esegue il programma con una sua memoria?
Inoltre leggendo un libro di sistemi operativi ho parecchi dubbi sul funzionamento della CPU, cioè leggo che essa preleva dalla memoria decodifica ed esegue le istruzioni, ma cosa succede quando eseguo un programma .exe? La cpu non dovrebbe eseguire le istruzioni presenti nel file eseguibile? Cosa mette in memoria e cosa preleva esattamente?
Inoltre leggendo un libro di sistemi operativi ho parecchi dubbi sul funzionamento della CPU, cioè leggo che essa preleva dalla memoria decodifica ed esegue le istruzioni, ma cosa succede quando eseguo un programma .exe? La cpu non dovrebbe eseguire le istruzioni presenti nel file eseguibile? Cosa mette in memoria e cosa preleva esattamente?
Risposte
"Darèios89":
QUando ho un programma in C++ ad esempio, io compilo, poi cosa succede? Viene generato un file assembly, che l' assemblatore traduce in linguaggio macchina binario pronto per essere eseguito dalla CPU?
Più o meno. Potresti farlo, ma normalmente il compilatore e l'assemblatore sono lo stesso programma. Il sorgente viene letto e convertito nel formato interno del compilatore (questa operazione si chiama parsing), poi trasformato in un altro formato corrispondente all'assembly. Se l'assembly fosse effettivamente generato poi l'assemblatore dovrebbe leggerlo e convertirlo nel suo formato, quindi si salta questo passaggio.
Comunque alcuni compilatori consentono di fare solo la fase di compilazione e danno in output il file assembly (es. gcc -c -S sorgente.c).
Se ho un linguaggio interpretato invece, il computer esegue un interprete, che a sua volta legge e converte ad una ad una le istruzioni e le esegue?
Non è detto che le istruzioni siano lette ed eseguite una alla volta, però il concetto è quello.
Gli interpreti moderni sono molto più complessi, ad esempio possono usare dei compilatori JIT (Just In Time). L'esecuzione viene monitorata e funzioni e metodi che vengono eseguiti spesso possono essere compilati dall'interprete in linguaggio macchina.
Quindi il programma vero e proprio non è eseguito dal pc, ma esso esegue l' interprete che è quello che esegue in realtà il programma usando una sua memoria e le sue strutture dati? Per esempio si dice che Java sia semiinterpretato perchè noi compiliamo, viene generato un file eseguibile dalla java virtual machine, quindi il pc esegue la virtual machine che a sua volta esegue il programma con una sua memoria?
Nelle versioni recenti Java appunto fa uso di un compilatore JIT. Inoltre esistono anche CPU particolari che eseguono nativamente il bytecode Java (quindi senza interpreti).
La motivazione originale per usare il bytecode era avere una via di mezzo tra portabilità e velocità di esecuzione. Fare il parsing del codice sorgente è lento e richiede molta memoria, mentre fare il parsing del bytecode invece è molto più efficiente. Inoltre il bytecode può essere ottimizzato. Eseguire il bytecode quindi è molto più efficiente di interpretare il codice sorgente, anche se meno efficiente del codice macchina (a meno di non usare compilatori JIT), ed ha il vantaggio di non dover ricompilare il programma per ogni architettura.
Inoltre ricorda che tutto dipende dalla particolare implementazione del linguaggio. Java può essere compilato in codice macchina usando ad esempio gcj. L'implementazione principale di Python (CPython) è un interprete scritto in C, ma esiste un'implementazione che lo compila nel "bytecode" della piattaforma .NET (IronPython), un interprete / compilatore JIT scritto in Python (PyPy). Esistono anche interpreti per C / C++.
Inoltre leggendo un libro di sistemi operativi ho parecchi dubbi sul funzionamento della CPU, cioè leggo che essa preleva dalla memoria decodifica ed esegue le istruzioni, ma cosa succede quando eseguo un programma .exe? La cpu non dovrebbe eseguire le istruzioni presenti nel file eseguibile? Cosa mette in memoria e cosa preleva esattamente?
Quando esegui un .exe il sistema operativo legge il programma, che ha una parte iniziale di dati che spiegano come deve essere eseguito, e lo carica in memoria. Il sistema operativo può anche modificare il codice eseguibile (ad esempio riordinare gli indirizzi di memoria). Poi vengono caricate le librerie dinamiche necessarie con lo stesso sistema. Poi il sistema operativo crea un processo e gli assegna l'area di memoria dove risiede il codice eseguibile del programma.
A questo punto lo scheduler dei processi può far partire il programma, quindi assegna alla CPU l'indirizzo del nuovo processo e la CPU prosegue con il ciclo "fetch, decode, execute". Periodicamente (mi sembra circa ogni 50 ms) il sistema operativo sostituisce il processo in esecuzione con un altro, in modo da simulare l'esecuzione in contemporanea di più programmi.
Inoltre le CPU moderne non eseguono direttamente il codice macchina, ma lo interpretano. Quando legge un'istruzione dalla memoria la CPU esegue una serie di istruzioni presenti in una memoria interna (chiamate microcodice) che "interpretano" l'istruzione letta.
Su internet trovi sicuramente una spiegazione esaustiva, comunque è un procedimento interno alla CPU, invisibile dall'esterno.
Wow....ti ringrazio per la spiegazione, una cosa che non ho capito bene è la portabilità. Si dice che è il vantaggio di Java essere un linguaggio "write once run everywhere". Cioè se ho praticamente il codice compilato portandolo su un altro sistema operativo dovrei poterlo eseguire solo con un JVM. Qual è il vantaggio rispetto a C/C++? Cioè io per questi ultimi ho bisogno di un compilatore, e lo devo scaricare o su linux o su windows, con Java devo sempre avere una JVM per potere eseguire il programma quindi questo vantaggio esegui ovunque dov' è?
Grazie delle delucidazioni.
Grazie delle delucidazioni.

La JVM specifica una particolare architettura che è la stessa per tutti gli ambienti su cui gira, quindi un sorgente Java viene compilato in un unico bytecode ed eseguito nello stesso identico modo dappertutto.
C e C++ invece hanno una marea di aspetti dipendenti dall'implementazione (con buona pace del "write once compile everywhere"): da quanti bit è composto un char, 8, 32, 27? Dipende dall'implementazione. La rappresentazione degli interi è big-endian o little-endian? Dipende dall'implementazione. In che ordine vengono valutati i parametri passati alle funzioni? Dipende dall'implementazione.
Java garantisce un minimo di compatibilità binaria tra versioni diverse. Invece ad esempio su Linux (almeno su alcune architetture) devi avere installata la stessa versione della libc che hai usato per compilare il programma C/C++. E anche su Windows devi installare il runtime del compilatore usato. Quindi hai versioni diverse anche per lo stesso sistema operativo, mentre su Java al massimo devi differenziare per versione della JVM.
Java offre una libreria enorme indipendente dal sistema operativo. Ad esempio il codice per accedere alla rete, per gestire i processi e thread o per l'interfaccia grafica è diverso su Windows e su sistemi POSIX. In C/C++ dovresti scrivere due versioni delle stesse funzioni ed attivare quella giusta su sistemi diversi. E ancora non funzionerebbe su sistemi che non sono Windows né POSIX. In Java c'è una sola versione che funziona ovunque (ovunque ci sia la JVM).
In sostanza in C/C++ per programmi non banali ti ritrovi sempre ad usare funzionalità specifiche del sistema corrente (quindi non portabili) oppure librerie che aumentano l'astrazione, mentre in Java è già tutto pronto.
Le eccezioni ci sono sempre, ci sono casi in cui anche in Java bisogna scrivere codice diverso per piattaforme diverse, ma in confronto a C/C++ la portabilità è nettamente a favore di Java (che però ha altri difetti rispetto ad altri linguaggi).
C e C++ invece hanno una marea di aspetti dipendenti dall'implementazione (con buona pace del "write once compile everywhere"): da quanti bit è composto un char, 8, 32, 27? Dipende dall'implementazione. La rappresentazione degli interi è big-endian o little-endian? Dipende dall'implementazione. In che ordine vengono valutati i parametri passati alle funzioni? Dipende dall'implementazione.
Java garantisce un minimo di compatibilità binaria tra versioni diverse. Invece ad esempio su Linux (almeno su alcune architetture) devi avere installata la stessa versione della libc che hai usato per compilare il programma C/C++. E anche su Windows devi installare il runtime del compilatore usato. Quindi hai versioni diverse anche per lo stesso sistema operativo, mentre su Java al massimo devi differenziare per versione della JVM.
Java offre una libreria enorme indipendente dal sistema operativo. Ad esempio il codice per accedere alla rete, per gestire i processi e thread o per l'interfaccia grafica è diverso su Windows e su sistemi POSIX. In C/C++ dovresti scrivere due versioni delle stesse funzioni ed attivare quella giusta su sistemi diversi. E ancora non funzionerebbe su sistemi che non sono Windows né POSIX. In Java c'è una sola versione che funziona ovunque (ovunque ci sia la JVM).
In sostanza in C/C++ per programmi non banali ti ritrovi sempre ad usare funzionalità specifiche del sistema corrente (quindi non portabili) oppure librerie che aumentano l'astrazione, mentre in Java è già tutto pronto.
Le eccezioni ci sono sempre, ci sono casi in cui anche in Java bisogna scrivere codice diverso per piattaforme diverse, ma in confronto a C/C++ la portabilità è nettamente a favore di Java (che però ha altri difetti rispetto ad altri linguaggi).
"Darèios89":
Si dice che è il vantaggio di Java essere un linguaggio "write once run everywhere".
E' un mito. La frase corretta è "write once, crash everywhere".

[ Non ho resistito.

"Rggb":
[quote="Darèios89"]Si dice che è il vantaggio di Java essere un linguaggio "write once run everywhere".
E' un mito. La frase corretta è "write once, crash everywhere".

[ Non ho resistito.

Non sono dello stesso parere.....io per fortuna non ho mai avuto problemi....^^
Al di là del fatto che finché rimani nello standard, il C è assolutamente portabile (il codice), esistono librerie che risolvono il problema della portabilità (per esempio le librerie Qt). Tutto sommato Java ha poi i suoi problemi (tanto per incominciare un immotivata bassa compatibilità con lo standard per i floating point). Il Java è comunque portabile solo dove ti viene detto che lo puoi portare (ci si dimentica un po' troppo spesso che è proprietario*)
Non esistono di per se linguaggi migliori, ma ci sono linguaggi più adatti di altri per particolari compiti. Ti farei comunque notare che la maggiorparte dei programmi proprietari per desktop, anche tra quelli multipiattaforma, usa il C++ (cosa che invece non penso valga per le app di cellulari e tablet). Questo principalmente perché il Java non è probabilmente sufficientemente performante per i loro scopi. In campo embedded si usa il C. In campo scientifico ci sono ancora molti che usano il fortran.
* per certi versi lo è di più di C#
Non esistono di per se linguaggi migliori, ma ci sono linguaggi più adatti di altri per particolari compiti. Ti farei comunque notare che la maggiorparte dei programmi proprietari per desktop, anche tra quelli multipiattaforma, usa il C++ (cosa che invece non penso valga per le app di cellulari e tablet). Questo principalmente perché il Java non è probabilmente sufficientemente performante per i loro scopi. In campo embedded si usa il C. In campo scientifico ci sono ancora molti che usano il fortran.
* per certi versi lo è di più di C#
"vict85":
Al di là del fatto che finché rimani nello standard, il C è assolutamente portabile (il codice), esistono librerie che risolvono il problema della portabilità (per esempio le librerie Qt). Tutto sommato Java ha poi i suoi problemi (tanto per incominciare un immotivata bassa compatibilità con lo standard per i floating point). Il Java è comunque portabile solo dove ti viene detto che lo puoi portare (ci si dimentica un po' troppo spesso che è proprietario*)
Non esistono di per se linguaggi migliori, ma ci sono linguaggi più adatti di altri per particolari compiti. Ti farei comunque notare che la maggiorparte dei programmi proprietari per desktop, anche tra quelli multipiattaforma, usa il C++ (cosa che invece non penso valga per le app di cellulari e tablet). Questo principalmente perché il Java non è probabilmente sufficientemente performante per i loro scopi. In campo embedded si usa il C. In campo scientifico ci sono ancora molti che usano il fortran.
* per certi versi lo è di più di C#
Ma la portabilità del java non deriva dal fatto che sia proprietario o meno, ma semplicemente perchè girando su una virtual machine standard per tutti i sistemi operativi non ci sono problemi di compatibilità.
Il fatto che java non sia utilizzato intensivamente per software desktop deriva proprio dalla virtual machine che sta in mezzo, che "penalizza" in un certo modo alcuni aspetti di performance