prof. Nunzio Brugaletta

Introduzione all’uso di Borland C++Builder

EnneBi - Programmazione
Il processo di compilazione - Ambienti integrati e C++ Builder - Applicazioni console su singolo file - Alcuni errori comuni - Esecuzione del programma - Il debugging dei programmi - Utilizzo degli strumenti di debugging -






Il processo di compilazione


Scelto un linguaggio di programmazione (per esempio C o C++) e codificato un programma, il problema che si pone è quello di fare diventare tale programma eseguibile da un computer. A tale scopo è necessario utilizzare un compilatore (nel nostro caso un compilatore C++) che è un particolare software che a partire da un programma scritto in un determinato linguaggio di programmazione (il programma sorgente C++) può generare un programma eseguibile. Tutto ciò è ottenuto dal compilatore traducendo in codice binario comprensibile dalla macchina le istruzioni contenute nel sorgente. Tale processo, che può variare e prevedere diverse fasi in dipendenza del compilatore stesso e del suo funzionamento, richiede dal programmatore l’esecuzione di alcune operazioni che possono essere ricondotte in breve alle seguenti:


In definitiva, da quanto esposto, per completare il processo di compilazione per la produzione del codice eseguibile, è necessario utilizzare una serie di strumenti software.

Quanto meno bisogna utilizzare: editor, compilatore, debugger. In alcuni casi, per completare l’opera del compilatore è necessario un linker, in altri casi, in dipendenza del tipo di compilatore, occorrono anche altri strumenti software, per esempio per l’esecuzione del programma compilato.

Inizio


Ambienti integrati e C++ Builder


Un ambiente di sviluppo integrato o IDE (Integrated Development Environment) è un software che racchiude, in un unico prodotto, tutto ciò che serve per sviluppare programmi. Utilizzando un ambiente integrato si può editare il sorgente, compilare, mandare in esecuzione, effettuare il debugging di un programma senza abbandonare l’ambiente di programmazione, con evidenti vantaggi dal punto di vista della rapidità di sviluppo.

Lo scopo di questi appunti è quello di fare prendere confidenza con C++ Builder della Borland (appunto un IDE) a cominciare dalla compilazioni di applicazioni su singolo file fino a scoprire gli strumenti per sviluppare applicazioni piùù complesse. La versione presa in considerazione è la 3, acclusa in versione completa e gratuita a CD che corredano alcune riviste in vendita nelle edicole, ma quanto verrà detto, vale anche per le versioni successive.


Una volta avviato, l’IDE C++ Builder, si presenta in questo modo:





Non è necessario comprendere immediatamente a cosa servano tutti gli strumenti visualizzati. Mano a mano che saranno necessari, si cercherà di vedere in che modo possano essere utili.

Inizio


Applicazioni console su singolo file


Si comincerà a utilizzare gli strumenti che mette a disposizione l’IDE per sviluppare il più semplice tipo di applicazioni: le applicazioni console su singolo file.

Una applicazione console su singolo file è un programma, in cui il sorgente si può conservare in un singolo file fisico su disco, che comunica con l’esterno utilizzando una interfaccia a caratteri (senza quindi l’’utilizzo di finestre, pulsanti, …).


Scegliendo dal menu File la voce New…, viene mostrata una finestra di dialogo da cui scegliere il tipo di applicazione da sviluppare: nel nostro caso una applicazione console.




Confermare la scelta. Confermando la successiva finestra di dialogo (tasto Finish) senza alcuna variazione viene mostrata la finestra in cui editare il programma.




La finestra Object Inspector può essere chiusa. Nell’esempio proposto non ci sono componenti da ispezionare: ci saranno quando si farà uso di componenti visuali (finestre, ecc…).

Ferme restando le caratteristiche standard di tutte le applicazioni (taglia, copia, incolla di parti di testo), l’ambiente di editazione del Builder è dotato di alcune caratteristiche interessanti:








Lasciando invariate le righe presentate in automatico dall’editor, si possono aggiungere le righe di codice del programma.


Nell’esempio seguente è presentato un programma per il calcolo del quoziente fra due numeri interi. Nel programma sono stati volutamente inseriti alcuni degli errori che si presentano più frequentemente:




Una volta scritto il programma è opportuno, prima di mandarlo in esecuzione, salvarne una copia su disco. Questa operazione può, come comune a tutte le applicazioni, essere effettuata scegliendo la voce Save As… dal menu File, la prima volta per assegnare il nome al file che contiene il sorgente del programma, scegliendo la voce Save, sempre dallo stesso menu, tutte le volte che si apportano modifiche e si vuole conservare una copia aggiornata.

Le stesse operazioni possono essere compiute premendo l’apposito pulsante di scelta rapida dalla barra degli strumenti:




Conviene chiarire che quando si salva su disco il file contenete il sorgente del programma, se per esempio si è scelto il nome Quoziente, verranno salvati su disco due file fisici:


Inizio


Alcuni errori comuni


Salvato su disco il programma (operazione che è sempre conveniente svolgere prima di lanciare l’esecuzione del programma), selezionando la voce Run dell’omonimo menu o premendo il pulsante corrispondente dalla barra delle applicazioni, il C++ Builder cerca di effettuare la traduzione del programma. Dopo qualche secondo, sotto la finestra dell’editor, viene mostrata una nuova finestra con l’elenco degli errori riscontrati:




Il cursore si posiziona nella riga del primo errore. In ogni caso, cliccando due volte sul messaggio di errore, si raggiunge subito la riga che può essere editata.



Il primo messaggio ci dice che il simbolo disv non è definito: il compilatore sta rilevando l’uso di un simbolo che non conosce. Effettivamente, fra le cose che conosce, è stata definita la variabile divs e non disv! (inversione lettere). L’avviso dell’errore viene evidenziato alla riga 14 perché è qui che, per la prima volta, si usa la variabile disv. In pratica è come se si usasse una variabile non dichiarata. Si fa notare che la colorazione della sintassi permette di evitare questo tipo di errori con le parole chiavi. Infatti se si fosse scritto itn al posto di int, questo non sarebbe visualizzato in grassetto come tutte le parole chiavi.



Il secondo messaggio è un Warning (Avviso). Non si tratta di un vero e proprio errore ma di una situazione che potrebbe generare malfunzionamenti durante l’esecuzione: se ci sono solo Warnings il programma viene compilato e mandato in esecuzione. In questo caso si è avvisati del fatto che si sta usando una variabile (il simbolo è conosciuto) senza che prima siano state effettuate operazioni di assegnazione. Infatti prima, sbagliando, si è effettuato l’input su disv.



Il terzo messaggio comunica che else non è posizionato correttamente. Se si esamina il listato si nota che qui, dimenticando di chiudere la parentesi graffa aperta nella riga della if, else è usato come se fosse una istruzione. In questo caso si può risalire facilmente al fatto di aver dimenticato una parentesi. In generale (si pensi, per esempio, ad un while), individuare dove si è dimenticata una parentesi, non è così immediato.



Il quarto messaggio indica appunto che manca una parentesi. Si noti che tale mancanza viene rilevata alla fine del programma (che qui coincida con la fine della if, è puramente casuale). Solo ora, infatti, il compilatore può rendersi conto della non equivalenza fra il numero delle parentesi aperte e quello delle parentesi chiuse. Se nel programma sono utilizzate molte parentesi, rintracciare la posizione dove si è dimenticata la parentesi, può essere una operazione molto lunga. Per questo motivo, come si accennava in precedenza, è comune trovare negli editor per programmatori la funzionalità di indentazione automatica. Un uso oculato di tale caratteristica permette di evitare questo tipo di errori.

Inizio

Esecuzione del programma


Corretti gli errori e salvata su disco la nuova versione del programma, si può procedere con una nuova compilazione. Se non vengono rilevati errori, viene generata una console virtuale nella quale verrà fatto girare il programma. In pratica si apre una nuova finestra che simula lo schermo di un computer, che funziona con interfaccia a caratteri, e si potrà osservare l’aspetto che avrà tale computer durante l’esecuzione del programma.



L’unica differenza fra la console virtuale e un computer reale consiste nel fatto che la console virtuale, una volta terminata l’esecuzione del programma, viene immediatamente chiusa e, quindi, se, come nell’esempio proposto, il programma termina effettuando un output, non si fa in tempo ad osservare il risultato prodotto. Per poter esaminare con calma i risultati è necessario bloccare la console. A tale scopo, per esempio, si possono effettuare sul sorgente del programma alcune aggiunte:


#include <conio.h>

getch();




Nella versione finale del programma (prima dell’ultima compilazione) le due nuove righe aggiunte possono essere eliminate.


La cartella dove sono conservati i file generati dall’IDE, oltre a Quoziente.cpp e Quoziente.bpr, ora conterrà pure Quoziente.exe: il file eseguibile che può essere lanciato fuori dall’ambiente integrato.

Inizio


Il debugging dei programmi


Il compilatore, avendo il compito di tradurre in eseguibili le istruzioni contenute nel sorgente, è in grado di segnalare gli errori sintattici. Alcuni esempi di questo tipo di errori sono stati presi in considerazione precedentemente: omettere una parentesi, un punto e virgola, digitare in modo errato una parola chiave.


Gli errori sintattici sono, in definitiva, semplici da correggere perché il compilatore fornisce una indicazione delle sue aspettative e, in genere, anche una indicazione del punto in cui si trova l’errore: è necessario solo prendere un poco di confidenza con i messaggi generati dal compilatore, avere presente le regole sintattiche del linguaggio e la correzione dell’errore è una operazione, in genere, abbastanza agevole.


Esiste, invece, una categoria di errori che possono essere anche piuttosto difficili da individuare. Si tratta degli errori logici. In altri termini: il programma viene compilato regolarmente, ma durante l’esecuzione, si evidenziano malfunzionamenti. Per esempio i risultati forniti in output differiscono da quelli attesi o, peggio ancora, i risultati non sono corretti solo in alcuni casi o, ancora, il programma si blocca in seguito ad errori determinati in sede di esecuzione (errori di run-time). Correggere gli errori logici del programma potrebbe sembrare una impresa quasi disperata: come si fa a sapere in che modo il computer genera i risultati visto che si possono vedere solo gli output finali?


L’’operazione di ricerca e correzione degli errori logici è chiamata debugging, dal termine inglese bug (baco, insetto), e, quindi, effettuare il debugging di un programma vuol dire togliere i bachi ovvero trovare e correggere le istruzioni che non fanno sì che i risultati prodotti siano quelli attesi. I programmi che aiutano lo sviluppatore nella ricerca dei bug si chiamano appunto debugger. C++Builder mette a disposizione una serie di strumenti per il debugging dei programmi, tutti accessibili dal menu Run o dal menu contestuale visualizzato in seguito al clic del tasto destro del mouse nell’editor.


Fra gli strumenti più comuni utilizzati per il debugging si esamineranno:


Inizio


Utilizzo degli strumenti di debugging


Riprendiamo da disco il programma Quoziente scritto in precedenza. A tale scopo si può procedere selezionando Open Project dal menu File o cliccando sul pulsante di scelta rapida della barra degli strumenti:







La prima azione che è opportuno compiere, all’apertura di una sezione di debugging, è quella di abilitare la visualizzazione della Watch List, cioè la finestra dove sono visualizzate tutte le variabili soggette ad attenzione. Per la visualizzazione basta selezionare Watches dal menu View. La visualizzazione della finestra viene anche selezionata in automatico non appena, con uno dei modi che si esamineranno più avanti, viene fissato il primo punto di attenzione. Se si clicca col tasto destro del mouse nella finestra Watch List, si può abilitare, dal menu contestuale, l’opzione Stay on Top. Ciò permette di vedere sempre in primo piano la finestra (tutte le altre finestre si vedranno sotto questa). In questo modo si avrà sempre facilmente visibile la finestra con le variabili e i valori in esse contenuti.


Per aggiungere la variabili, alla Watch List si può operare, per esempio, in uno dei due modi specificati appresso:




  1. Si porta il cursore in qualsiasi lettera che componga il nome della variabile che si vuole aggiungere alla Watch List

  2. Si clicca col pulsante destro del mouse

  3. Si sceglie Add Watch at Cursor dal menu contestuale



  1. Si clicca col pulsante destro del mouse nella finestra Watch List

  2. Si sceglie Add Watch dal menu contestuale

  3. Si inserisce, nel campo Expression della finestra di dialogo visualizzata, il nome della variabile. Si noti che, essendo libero l’inserimento nel campo, si può inserire, per esempio, qualsiasi espressione che coinvolga anche più variabili



Si può ripetere uno dei procedimenti esaminati per ognuna delle variabili, o espressioni, che si vogliono tenere in osservazione, così come, se si vuole eliminare una variabile dalla Watch List, basta evidenziarla e premere il tasto Canc o scegliere dal menu contestuale, visualizzato col clic destro, la voce Delete Watch. Nel caso del programma Quoziente, si possono, per esempio, aggiungere alla Watch List le due variabili div e divs.


Si aggiunga adesso un breakpoint nella if di Quoziente. In questo modo, prima di eseguire la struttura di controllo, il programma si bloccherà permettendo l’esame dei valori contenuti nelle variabili. Per aggiungere il breakpoint, portare il cursore all’inizio della riga del programma che contiene la if e, dal menu contestuale mostrato al clic destro del mouse, scegliere Toggle Breakpoint. Tale opzione funziona da interruttore: se si sceglie una seconda volta, il breakpoint viene tolto.




Si può, ora, lanciare l’esecuzione del programma ed introdurre gli input. Subito dopo l’inserimento del secondo input, il programma si blocca:




A questo punto, se per esempio i valori riscontrati non sono quelli attesi, si può bloccare in maniera definitiva l’esecuzione del programma e tornare all’editor per apportare le opportune correzioni. Per interrompere il programma basta selezionare Program Reset dal menu Run.


Si può continuare l’esecuzione del programma:



Per eseguire le istruzioni passo-passo si possono utilizzare i pulsanti di scelta rapida dalla barra degli strumenti:





Ora si può reiterare il procedimento esposto per osservare la sequenza delle operazioni effettivamente eseguite durante l’elaborazione, uscire dalla sezione di debugging per correggere eventuali errori riscontrati, terminare l’’esecuzione del programma.


La pressione di uno qualsiasi dei due pulsanti della barra degli strumenti produce, nel caso del programma Quoziente, sempre gli stessi risultati. Il comportamento però differisce se l’istruzione da eseguire è la chiamata ad una funzione:




La pressione del tasto Trace into permette di passare all’esecuzione della prossima istruzione. L’istruzione successiva alla chiamata della funzione è la prima istruzione contenuta nella definizione della funzione, quindi, l’esecuzione del programma si blocca alla prima istruzione della funzione. Si entra dentro la funzione.



Anche la pressione del tasto Step over provoca il passaggio alla prossima istruzione eseguibile solo che, stavolta, la chiamata alla funzione è vista come singola istruzione. In altri termini l’esecuzione delle singole istruzioni della funzione non viene tracciata, si passa direttamente alla istruzione successiva alla chiamata di funzione. Ovviamente gli effetti, delle istruzioni contenute nella definizione della funzione, saranno osservabili nella Watch List. Le istruzioni contenute nella definizione della funzione sono in ogni caso, come giusto, eseguite: solo l’evidenziazione dell’esecuzione (trace) salta le istruzioni della funzione.


Non essendoci, nel programma Quoziente, alcuna chiamata di funzione l’effetto della pressione dei due tasti coinciderà e, quindi, diventa indifferente, nell'esempio proposto, quale dei due tasti si sceglie per effettuare il trace del programma.

Inizio

 


http://www.ennebi.cjb.net

nunziob@ennebi.cjb.net