AngoLinux

Convenzioni di scrittura di programmi C e Assembler

- A cura del Prof. Stefano Salvi -



Un programma può essere scritto in molti modi. Possono essere usati algoritmi diversi per risolvere lo stesso problema, alcuni migliori ed altri peggiori.
Oltre agli algoritmi, anche la presentazione del programma può essere molto diversa.
Lo stesso programma, presentato in forma diversa, può risultare più leggibile e chiaro o meno.
In una realtà produttiva, come anche la scuola, si deve sempre tener presente che un programma deve essere elaborato da più persone. Inoltre ogni programma ha un ciclo di vita, per cui in periodi diversi e da persone diverse dovrà essere letto, compreso e modificato.
Per questo motivo è indispensabile definire uno stile standard di codifica che deve essere seguito in maniera assoluta, per garantire una trasferibilità ed una manutenibilità nel tempo.
Quando si intraprende un nuovo progetto, normalmente, il team dei programmatori ed analisti si accorda su di uno stile comune. Se però un programmatore si aggiunge in un secondo tempo, deve adeguarsi allo stile già consolidato, pena grosse difficoltà di scambio con il resto del team.
Se il team è ben organizzato le convenzioni di stile vengono anche formalizzate in un documento.
Nel nostro caso questo è il documento di definizione dello stile.

Stile e regole per la scrittura di programma C e C++

NOTA 1: queste indicazioni non possono considerarsi complete. Verranno di mano in mano aggiornate, man mano che nuove convenzioni verranno codificate o che si vedrà che alcune indicazioni sono diventate obsolete o sono poco chiare.

NOTA 2: questi stili e procedure sono generali ed vanno applicati per tutta la durata del corso. Inizialmente gli studenti conoscono solo parte del linguaggio C, quindi alcuni dei punti, che si riferiscono a funzioni, parametri, prototipi o linguaggio C++ non saranno applicabili. Nel momento in cui la teoria avrà introdotto le conoscenze necessarie, ogni punto diventerà obbligatorio.

  • Ogni programma va prima progettato e poi realizzato. Prima di cominciare a scrivere definizioni o codice occorre aver deciso con precisione cosa si deve fare. Meglio se questo processo decisionale è scritto. In particolare, se la stesura di un programma prenderà più lezioni di laboratorio la stesura del progetto è indispensabile. Il posto più opportuno per scriverlo è il commento iniziale del programma.
    Se l'analisi viene redatta invece in un documento estrerno, sarà comunque importante lasciare qui un sunto dell'analisi stessa ed un riferimento al documento esterno.
  • Ove non sia esplicitamente richiesto o non si sia deciso di utilizzare delle classi, non compilare come C++, ma come C standard.
  • Ogni programma deve cominciare con un commento. Questo commento iniziale deve contenere:
    1. Nome, cognome di tutti i componenti del gruppo
    2. Data di inizio della stesura del programma
    3. Nome del file, per garantire chiarezza nella stampa
    4. Testo del problema, scritto in maniera più chiara e descrittiva possibile
    5. Assunzioni aggiuntive o limitazioni del programma
    6. Eventuali note sugli algoritmi usati
    in paritcolare, le note sugli algoritmi sono fondamentali per garantire la coerenza nella stesura del programma che verrà scritto da più persone e nell'arco di più lezioni di laboratorio.
    Questo commento iniziale va scritto prima di cominciare a scrivere codice o dichiarazioni.
    NOTA: negli esempi che seguono, il testo del problema non è riportato nel commento iniziale per concisione, visto che compare nella documento subito prima del sorgente.
  • Ogni sorgente dovrà contenere nell'ordine:
    1. Commento iniziale
    2. Istruzioni #include per tutti i file da includere (attenzione! includere solo i file necessarie)
    3. Diciarazioni di constanti, strutture e tipi enumerativi
    4. Definizione di variabili
    5. Prototipi delle funzioni
    6. Definizione delle funzioni
    La funzione main va messa come prima funzione.
  • I nomi delle variabili, strutture, costanti e funzioni devono essere significativi.
  • Sono da evitare nomi troppo lunghi. È opportuno cercare in linea di massima di contenere la lunghezza dei nomi sotto i 16 caratteri.
  • Se un nome deriva dalla concatenazione di più parole è preferibile evidenziare con iniziali maiuscole le parole seguenti alla prima, piuttosto che usare il carattere _, che aumenta la lunghezza del nome, per separarle.
  • I nomi delle costanti vanno scritti tutti in maiuscolo (in questo caso usare gli _ per separare le parole, se il nome è composto)
  • I commenti sulla stessa riga delle costanti vanno fatti con /* ... */ e non con // .... perchè alcuni compilatori sostituiscono l'intera riga della costante, compreso il commento, generando errori difficili da rintracciare.
  • Se una costante non è costituita solamente da un valore semplice, ma da un'espressione (come ad esempio #define TOTALE (A+B)) ricordarsi di mettere tra parentesi l'espressione, come nell'esempio. A TOTALE viene sostituito il testo che segue. Se noi, per esempio, adesso calcolassimo x=TOTALE*2, con le parentesi risulta correttamente x=(A+B)*2, ma senza sarebbe diventato x=A+B*2, che viene calcolato come x=A+(B*2), quindi errato.
  • I nomi di strutture, variabili, funzioni o altro vanno scritti tutti in minuscolo, salvo per le iniziali, come indicato precedentemente.
  • Nelle dichiarazioni di tipi (struct, union, enum) o nelle inizializzazioni di variabili all'interno delle definizioni la { che apre il blocco va posta di seguito al nome del tipo all'uguale dell'inizializzazione, sulla stessa riga.
    Nel caso delle struct o union, i vari campi andranno su righe separate, indentati rispetto alla dichiarazione, mentre la graffa di chiusura andrà allineata con l'inizio della dichiarazione, su di una riga a sè stante.
    Per gli enum e le inizializzazioni, se trovano posto sulla stessa riga della dichiarazione stessa, andranno chiusi con la graffa sulla stessa riga, altrimenti andranno indentati e su righe successive, con la graffa su una riga a sè stante, allineata con la definizione.
  • Le variabili globali vanno usate solo se strettamente indispensabile.
  • Per ogni costante, ogni struttura, ogni campo di struttura ed ogni variabile locale occorre indicare, con un commento, che funzione ha.
  • Nelle funzioni o nei costrutti if / else, for, while, switch la { di apertura del blocco va allineata sotto la prima lettera del costrutto (del tipo di ritorno, per le funzioni). La } di chiusura del blocco va allineata esattamente sotto la { di apertura.
  • Nel costrutto do ... while la { di apertura va posta sulla stessa riga del do, quindi si va a capo; la } di chiusura va allineata sotto la d di do, seguita dal while.
  • Le dichiarazioni di variabili locali vanno allineate esattamente sotto la { di apertura del blocco in cui sono definite.
  • Anche se il C++ lo consente, le variabili locali non vanno definite nel punto del primo utilizzo (ad esempio la variabile del for definita nel for stesso) ma all'inizio del blocco in cui sono utilizzate.
  • Tutte le istruzioni contenute in un blocco vanno indentate rispetto all'alineamento del blocco stesso (che sia la { di apertura o il do). Per evitare di avere sorgenti che eccedano la larghezza dello schermo è preferibile indentare i un paio di spazi, invece che di un tab.
  • Nell'espressione ternaria (<condizione> ? <valore per vero> : <valore per falso>) la condizione va sempre messa tra parentesi.
  • Ove possibile l'epsressione ternaria va messa su di una sola riga. Se è necessario, si deve andare a capo dopo il ? dopo il :.
  • Se l'espressione ternaria è annidata (<valore per vero> o <valore per falso> sono a loro volta espressioni ternarie) le espressioni ternarie interne vanno messe tra parentesi.
  • Una funzione deve eseguire un compito. Non è opportuno scrivere funzioni che contengano il codice per fare molte cose assieme. Piuttosto, scrivere le funzione per i singoli compiti ed una ulteriore funzione che svolga il compito complesso, invocando le funzioni precedenti.
  • Le funzioni comunicano con il resto del programma tramite i parametri ed il valore di ritorno. In particolare i parametri vanno normalmente dal programma alla funzione ed il valore di ritorno dalla funzione al programma. Se l'interazione non è questa, occorre documentarlo molto bene. In particolare:
    • Se una funzione modifica delle variabili globali
    • Se una funzione ha dei parametri passati per riferimento che vengono modificati
    Attenzione che i vettori e le strutture sono sempre passati per riferimento alle funzioni, quindi occorre documentare molto bene il loro uso.
    Sarebbe auspicabile usare la parola chiave const per i parametri (strutture o vettori) in ingresso.
  • Se si usano i prototipi per le funzioni, indicare sempre i nomi dei parametri, oltre ai tipi. I tipi servono al compilatore, i nomi al programmatore. Inoltre, commentare ogni prototipo indicando il compito della funzione ed i parametri usati. Questo commento deve essere più sintetico di quello prima della definizione della funzione. Si deve puntare a descrivere più la funzione che i parametri. Meglio se il commento è breve e stà sulla stessa riga del prototipo.
  • Prima di ogni funzione, eccetto che per la main, è necessario fare un commento, molto evidente (per individuare alla svelta le funzioni, quando le si cerca), che contenga:
    • Scopo della funzione
    • Significato e valori leciti dei parametri, uno per uno
    • valori di ritorno nei vari casi
    • Eventuali parametri passati per riferimento modificati all'interno della funzione
    • Eventuali effetti collaterali sulle variabili globali
  • Occorre mettere commenti su quasi tutte le istruzioni. I commenti devono essere significativi. Ad esempio la riga:
    	x++;	// Incrementa x
    
    non ha un commento significativo, mentre la riga:
    	x++;	// Sposta l'oggetto a destra
    
    lo ha.
  • I commenti devono essre sintetici. Le istruzioni devono comunque essrere la cosa che spicca maggiormente nella lettura; il compito dei commenti è di renderle di più comprensbili, non di sommergerle.
  • I commenti devono essere aggiornati. Se modifichiamo l'uso di una variabile o l'algoritmo di una funzione e non modifichiamo il commento che lo spiega, invece di rendere più facile la comprensione il commento la ostacolerà.
  • I commenti vanno separati di almeno uno spazio od una tabulazione dall'istruzione che descrivono.
    Se il commento, inserito dopo l'istruzione, andrà troppo a destra, lo metterò sulla riga precedente, allineato con l'istruzione.
    Cercherò per quanto possibile di incolonnare tutti i commenti in coda alle istruzioni.
  • È opportuno separare con una linea vuota i gruppi funzionali che possono essere individuati in una funzione.
  • Quando l'algoritmo utilizzato in una funzione non è evidente è necessario documentarlo molto bene con un commento sufficientemente esteso.

Appendice sull'Assembler

  • Ogni programma assembler deve cominciare con lo stesso commento dei programmi C/C++
  • Le label devono essere allineate al bordo sinistro
  • Le istruzioni devono essere indentate esattamente di un tabulatore
  • I parametri delle istruzioni devono essere separate dall'opcode di un tabulatore. Ad esempio:
    main:
    	mov	sp,#8fh	; Inizializza lo stach per le subroutine
    
  • Prima di ogni subroutine vagrave posto un commento. Questo commento deve contenere:
    1. Un commento molto evidente, contenente il nome della funzione
    2. Una descrizione del funzionamento della subroutine, contenete anche eventuali note sull'algoritmo usato
    3. un elenco dei parametri di ingresso (input:) che elenchi tutti i dati usati dalla funzione, indicando in che registri/variabili globali vanno posti
    4. Un elenco dei valori ritornati (output:) che indichi che cosa viene ritornato ed in quali registri/variabili globali saranno lasciati
    5. Un elenco dei registri/variabili globali modificate dalla subroutine (modifica:), ed il cui valore non è stato ripristinato prima di terminare la subroutine.
    Tutte queste informazione devono comparire sempre nel commento prima di ogni subroutine.
    Le parole input:, modifica: e output: devono comparire necessariamente nel commento, all'inizio di una riga.

[Home Page dell'ITIS "Fermi"] [Indice Terza] [Precedente] [Successivo]

© Ing. Stefano Salvi - Released under GPL licence