Compila, poi esegui
Ora che hai installato un compilatore, far girare un programma C++ è un ciclo in due passaggi. A differenza di un linguaggio di scripting, in cui un interprete legge il file riga per riga, il C++ prima compila il sorgente in un eseguibile nativo, cioè un binario autonomo di codice macchina, e poi esegui direttamente quel binario. A runtime non c'è nessun interprete tra il tuo programma e la CPU.
Questa separazione è il motivo per cui il C++ è veloce, e anche il motivo per cui un errore di sintassi ti ferma in fase di compilazione invece che a metà esecuzione. Il compilatore controlla l'intero file prima di produrre qualsiasi cosa.
Puoi eseguire qualsiasi esempio autonomo direttamente in questa pagina: l'editor qui sotto lo compila e lo esegue per te. Ma vale la pena sapere cosa succede sul tuo computer, perché è lì che vivono i progetti veri.
Il ciclo compila-esegui sul tuo computer
Supponiamo che tu abbia salvato questo come main.cpp:
#include <iostream>
using namespace std;
int main() {
cout << "Hello from the terminal" << endl;
return 0;
}
Apri un terminale nella cartella che contiene il file e invoca il compilatore. Il compilatore più comune è g++ (parte di GCC); clang++ funziona in modo identico per tutto ciò che vedrai qui:
g++ main.cpp -o main
Se il codice compila senza problemi, g++ non stampa nulla e crea un nuovo file accanto al sorgente: un eseguibile chiamato main (o main.exe su Windows). Quel binario è codice macchina: non è testo leggibile ed è legato al tuo sistema operativo e alla tua CPU. Ora eseguilo:
./main
Hello from the terminal
Su Windows lo eseguiresti come main.exe (o semplicemente main) dallo stesso terminale. Il ./ su macOS e Linux dice alla shell "il programma è proprio qui in questa cartella, non da qualche parte nel PATH": un passaggio che i principianti dimenticano, per poi chiedersi perché main risponda command not found.
Cosa fa -o (e a.out)
L'opzione -o dà il nome all'output. Se la togli, g++ compila comunque, ma scrive l'eseguibile con un nome predefinito: a.out su macOS/Linux, a.exe su Windows.
g++ main.cpp # produces a.out, not main
./a.out
Questo confonde tantissime persone: compilano, non vedono errori, eseguono ./main e ottengono No such file or directory, perché il binario in realtà si chiama a.out. Passa sempre -o, così sai esattamente cosa stai eseguendo.
Compili una volta per ogni modifica al sorgente. Dopodiché l'eseguibile è indipendente: puoi lanciare ./main cento volte senza ricompilare. Devi eseguire di nuovo g++ solo dopo aver modificato il file .cpp.
Scegliere uno standard C++
Il C++ ha delle versioni, C++11, C++14, C++17, C++20 e C++23, e ognuna aggiunge funzionalità al linguaggio. Il problema: il tuo compilatore sceglie uno standard predefinito che potrebbe essere più vecchio di quanto pensi, quindi del codice moderno può non compilare senza un motivo evidente. Imposta lo standard in modo esplicito con -std:
g++ -std=c++17 main.cpp -o main
g++ -std=c++20 main.cpp -o main
Ecco del codice che usa una funzionalità di C++17 (gli structured binding). Nell'editor compila senza problemi, ma sul tuo computer richiede -std=c++17 o superiore:
Se vedi un errore come 'structured bindings' only available with '-std=c++17', la soluzione non è nel tuo codice: basta aggiungere l'opzione -std giusta. In tutto questo corso, dai per scontato C++17 o superiore.
Attiva gli avvisi
Un programma C++ può compilare senza errori ed essere comunque sbagliato. Se glielo chiedi, il compilatore ti segnala il codice sospetto prima che ti morda a runtime. Aggiungi -Wall -Wextra:
g++ -std=c++17 -Wall -Wextra main.cpp -o main
Considera questo programma. Compila senza -Wall, ma contiene un vero bug: legge una variabile a cui non è mai stato dato un valore, il che è comportamento indefinito:
#include <iostream>
using namespace std;
int main() {
int count; // never initialized
cout << count << endl; // reads garbage - undefined behavior
return 0;
}
Con gli avvisi attivi, il compilatore lo segnala:
warning: 'count' is used uninitialized [-Wuninitialized]
Prendi l'abitudine di compilare con -Wall -Wextra fin dal primo giorno. Gli avvisi sono il compilatore che ti fa una revisione del codice gratis; ignorarli è il modo in cui i bug subdoli sopravvivono. Qui la correzione è semplicemente int count = 0;.
Leggere gli errori del compilatore
Quando g++ rifiuta il tuo codice, indica il file, la riga e cosa è andato storto. Imparare a leggere quei messaggi è metà del lavoro per sbloccarti. Ecco il classico, un punto e virgola mancante:
#include <iostream>
using namespace std;
int main() {
cout << "Oops" // no semicolon
return 0;
}
main.cpp:5:5: error: expected ';' before 'return'
5 | return 0;
| ^~~~~~
Alcune cose da notare. L'errore riporta la riga 5, ma lo sbaglio è alla riga 4: il compilatore si accorge che manca un punto e virgola solo quando arriva al token successivo. Quindi, quando un errore indica una riga che sembra corretta, controlla la riga precedente. main.cpp:5:5 significa file, riga e poi colonna. Correggi l'unica cosa che indica e ricompila, senza andare a tentativi.
Gli errori del compilatore significano che non è ancora stato eseguito nulla. Sono diversi dagli errori a runtime, in cui il programma è partito e poi si è bloccato. Individuare gli errori in fase di compilazione, prima ancora che il programma venga eseguito, è uno dei maggiori punti di forza del C++.
Un programma di verifica
Eseguilo nell'editor, oppure salvalo come main.cpp ed esegui g++ -std=c++17 -Wall main.cpp -o main e poi ./main sul tuo computer. Se compaiono tutte e tre le righe, la tua toolchain funziona dall'inizio alla fine:
Qui compaiono tre cose che incontrerai a breve come si deve: una variabile int, un vector (l'array ridimensionabile del C++) e cout per l'output. Per ora basta che il programma compili e stampi le tre righe in ordine.
Prossimo: Sintassi del C++
Hai compilato ed eseguito qualche programma, ma finora abbiamo sorvolato sulla punteggiatura: le righe #include, le graffe, i punti e virgola, int main() e il motivo per cui ogni riga ha quell'aspetto. La prossima pagina scompone la sintassi del C++ pezzo per pezzo, così la struttura smette di sembrare codice di rito e inizia ad avere senso.
Domande frequenti
Come si compila ed esegue un programma C++?
Salva il codice come main.cpp, apri un terminale in quella cartella ed esegui g++ main.cpp -o main per produrre un eseguibile. Poi avvialo con ./main su macOS/Linux o main.exe su Windows. Compili una volta; puoi eseguire il binario risultante tutte le volte che vuoi.
A cosa serve l'opzione -o in g++?
-o dà il nome al file di output. g++ main.cpp -o hello crea un eseguibile chiamato hello. Se ometti -o, g++ usa il nome predefinito a.out (o a.exe su Windows), ed è per questo che i principianti spesso finiscono per eseguire un file che non sapevano di aver creato.
Come si compila il C++ con uno standard specifico come C++17 o C++20?
Passa l'opzione -std: g++ -std=c++17 main.cpp -o main oppure -std=c++20. Senza di essa, il compilatore usa il proprio default, che potrebbe essere più vecchio di quanto pensi, quindi funzionalità recenti come gli structured binding o <ranges> potrebbero non compilare finché non imposti lo standard esplicitamente.