Sorgenti multifile

Durante la realizzazione di un software costituito da un main() e numerose funzioni, può risultare utile dividere “fisicamente” il codice del programma, in più file sorgenti. In questo modo diventa più facile apportare modifiche e leggere il codice, soprattutto nei programmi di grandi dimensioni. Inoltre, siccome in certi casi il compilatore può compilate le singole parti anche individualmente, in caso di modifiche ad uno dei file sorgenti non è necessario ricompilare tutto il programma, ma solo il file modificato. Comunque tutti i file sorgente appartenenti allo stesso programma dovranno essere contenuti in una sola cartella.

Nel seguente esempio riprenderemo un semplicissimo programma, che sarebbe stato inutile dividere in più file, ma che comunque divideremo per esercizio, per poter capire come procedere anche nei casi più complicati.

main.cpp
/** @file main.cpp 
*
*/
 
#include <iostream>
 
int triplicare(int x) 
{
  return 3*x;
}
 
int main()
{
  int mioNumero,mioTriplo;
 
  std::cout << "Per favore scrivi un numero intero: ";
  std::cin >> mioNumero;
  mioTriplo = triplicare(mioNumero); // chiamata della funzione
  std::cout << "il triplo di " << mioNumero << " vale "
            << mioTriplo << endl;
  return 0;
}

La cosa che sembra più semplice da fare è quella di dividerlo in due file sorgenti.

ATTENZIONE: c'è grave un errore nel seguente file main.cpp! Infatti non basta spezzare il codice in due parti… per comprendere l'errore bisogna aver compreso l'importanza delle dichiarazioni.

triplicare.cpp
/** @file triplicare.cpp 
*
*/ 
int triplicare(int x) 
{
  return 3*x;
}
main.cpp
/** @file main.cpp 
*
*/ 
 
#include <iostream>
// ERRORE qui manca una dichiarazione
 
int main()
{
  int mioNumero,mioTriplo;
 
  std::cout << "Per favore scrivi un numero intero: ";
  std::cin >> mioNumero;
  mioTriplo = triplicare(mioNumero); // chiamata della funzione
  std::cout << "il triplo di " << mioNumero << " vale "
            << mioTriplo << endl;
  return 0;
}

NOTA: bisogna usare #include <iostream> SOLO dove serve! Cioè dove si vuole fare Input/Output.

Quando il compilatore legge il contenuto del file main() trova la chiamata alla funzione triplicare() ma non può verificarne la correttezza del passaggio dei parametri. È necessario far precedere il main() con la dichiarazione della funzione che si vuole usare.

int triplicare(int x);

Dopo questa correzione, i due file sorgente non vanno compilati separatamente, bisogna comunicare al compilatore che da questi due file sorgente si deve ottenere un unico file eseguibile.

  • Il primo comando serve a generare due file oggetto (compilatore)
    • g++ -c main.cpp triplicare.cpp
  • Il secondo comando serve a collegarli in un unico file eseguibile (linker)
    • g++ main.o triplicare.o -o triplica.exe

In questo modo il programma viene compilato senza errori, ma il codice può essere ancora migliorato. Infatti, se per poter usare stdcout è necessaria la direttiva include, allo stesso modo, una simile direttiva potrebbe essere utilizzata anche per usare triplicare(). Si può creare un nuovo file di intestazione (header file) chiamato triplicare.h e contenente le dichiarazioni di tutte le funzioni del file triplicare.cpp, includendolo al posto della precedente dichiarazione di triplicare(). Anche se in questo semplice caso esiste una sola funzione. Ecco come si presenterebbe la soluzione finale: <file c triplicare.h> / @file triplicare.h * */ int triplicare(int x); </file> <file c triplicare.cpp> / @file triplicare.cpp * */ int triplicare(int x) { return 3*x; } </file> <file c main.cpp> / @file main.cpp * */ #include <iostream> #include “triplicare.h” int main() { int mioNumero,mioTriplo; stdcout « “Per favore scrivi un numero intero: ”; stdcin » mioNumero; mioTriplo = triplicare(mioNumero); chiamata della funzione stdcout « “il triplo di ” « mioNumero « “ vale ” « mioTriplo « endl; return 0; } </file> La differenza tra le virgolette di “triplicare.H” e <iostream> sta nel differente percorso dei file. Le virgolette si usano quando uso un percorso relativo agli altri file sorgente. Si può pensare a iostream come all'interfaccia che permette di usare std::out e a triplicare.h come all'interfaccia che permette di usare triplicare(). Nulla vieta di racchiudere tutti gli header necessari al main.cpp in un nuovo header, main.h <file c main.h> /** @file main.h * */ #include <iostream> #include “triplicare.h” </file>

  • appunti3s/sorgenti_multifile.txt
  • Last modified: 2018/04/25 07:55
  • (external edit)