C Coding Standards
FB - 01.2023 - v1.0
C Coding Standard
Prima di imparare a scrivere programmi perfettamente funzionanti e performanti bisogna imparare a scrivere codice chiaro e facilmente comprensibile, per noi e per le persone appartenenti al nostro gruppo di lavoro. Diventa quindi importante rispettare, durante la scrittura del codice, stili e regole condivise.
Uno standard di codifica C è un insieme di regole per il codice sorgente adottato da un team di programmatori che lavorano insieme su un progetto, come la progettazione di un sistema embedded. I team di programmazione e le aziende scrivono i loro standard di codifica C per una serie di motivi, ma spesso litigano internamente su quali regole seguire.
2
© FB - 01.2023
Indice
Introduzione
Concetto di standard di codifica
4
Convenzioni
La manutenzione del software è un'attività critica, il tempo impiegato per organizzare, documentare e testare il codice durante le fasi iniziali di sviluppo verrà ampiamente restituito in tutta la successiva durata del progetto software.
Il tempo risparmiato nello scrivere codice disorganizzato e non documentato verrà speso in futuro per la correzione degli errori e per l’implementazione di modifiche o nuove funzionalità.
Un project manager, dovrebbe premiare i buoni comportamenti e punire le cattive pratiche.
Dal momento che molti degli sforzi per lo sviluppo del software sono dati dalla manutenzione, dovremmo cercare di creare moduli software facili da modificare. Dovremmo aspettarci il nostro codice venga letto da un altro programmatore in futuro, il cui compito sarà quello di apportare modifiche.
Potremmo essere tentati di abbandonare un progetto software una volta che il sistema è in esecuzione, ma questo breve tempo che potremmo risparmiare non organizzando, documentando e testando andrà perso molte volte in futuro quando sarà il momento di aggiornare il codice.
5
© FB - 11.2021
C Coding Standards
Gli standard di codifica sono un insieme di regole e linee guida che aiutano a scrivere codice pulito, leggibile e facile da mantenere. Essi sono importanti perché aiutano a garantire che il codice sia consistente e facile da comprendere, sia per chi lo scrive che per chi lo legge. Ciò rende più semplice trovare e correggere eventuali errori nel codice, migliora la manutenibilità e la leggibilità del codice e aumenta la qualità generale del progetto.
In generale gli standard di codifica coprono diverse aree, come:
Inoltre un'altra importante caratteristica di un buono standard di codifica è che deve essere condiviso e adottato dall'intera comunità di sviluppatori, in questo modo si garantisce che tutti i membri del team di sviluppo siano allineati e che il codice sia scritto in modo coerente.
6
© FB - 01.2023
Struttura del codice
Come organizzare il codice in modo efficiente e leggibile
7
Struttura del codice
La struttura del codice si riferisce all'organizzazione e alla disposizione del codice all'interno di un programma o di un progetto. La struttura del codice è importante perché aiuta a rendere il codice facile da leggere, comprendere e mantenere. Una buona struttura del codice deve essere semplice, coerente e logica.
Ci sono diverse tecniche per organizzare la struttura del codice, alcune delle più comuni sono:
8
© FB - 01.2023
Struttura del codice
In generale, la scelta della tecnica di organizzazione dipenderà dalle esigenze specifiche del progetto e dalle preferenze degli sviluppatori. Ciò che è importante è che la struttura del codice sia coerente e logica, in modo che sia facile da comprendere e da mantenere. È inoltre importante che la struttura del codice sia documentata, in modo che gli sviluppatori possano comprendere le motivazioni dietro alla sua progettazione e che sia facile per i nuovi sviluppatori di entrare nel progetto.
Inoltre è importante che la struttura del codice sia flessibile, in modo che possa essere facilmente modificata e migliorata man mano che il progetto si evolve. Ciò significa che gli sviluppatori devono essere pronti a rivedere e a riorganizzare il codice in base alle nuove esigenze del progetto.
In sintesi, una buona struttura del codice è fondamentale per garantire che il codice sia facile da leggere, comprendere e mantenere, e aiuta a rendere il progetto più robusto e scalabile.
9
© FB - 01.2023
Sezioni e organizzazione del codice
10
© FB - 11.2021
Inclusione delle librerie
Quando includiamo delle librerie segniamo come commento quali funzioni stiamo utilizzando
//------------------------------------------------------------------------------------------
//=== INCLUDES =============================================================================
//------------------------------------------------------------------------------------------
#include <unistd.h> // read, write, close
#include <stdlib.h> // exit
#include <stdio.h> // printf
#include <string.h> // strlen
11
© FB - 10.2019
Sezioni dei file.c
Rendere evidenti tramite dei commenti separatori le varie sezioni del file
//------------------------------------------------------------------------------------------
//=== INCLUDES =============================================================================
//------------------------------------------------------------------------------------------
//=== LOCAL CONSTANTS ======================================================================
//=== LOCAL FUNCTION PROTOTYPES ============================================================
//=== LOCAL VARIABLES ======================================================================
//=== LOCAL FUNCTIONS ======================================================================
//=== FUNCTIONS DEFINITIONS ================================================================
//=== GLOBAL FUNCTIONS =====================================================================
//=== MAIN PROGRAM =========================================================================
//=== ARDUINO MAIN PROGRAM (setup e loop) ==================================================
//------------------------------------------------------------------------------------------
12
© FB - 10.2019
Sezioni dei file.h
Rendere evidenti tramite dei commenti separatori le varie sezioni del file
//------------------------------------------------------------------------------------------
//=== INCLUDES =============================================================================
//------------------------------------------------------------------------------------------
//=== CONSTANTS ============================================================================
//=== GLOBAL FUNCTION PROTOTYPES ===========================================================
//=== TYPE DEFINITIONS (typedef) ===========================================================
//------------------------------------------------------------------------------------------
13
© FB - 10.2019
Il file main.c nel firmware dei sistemi embedded
14
© FB - 10.2019
Naming conventions
Come dare nomi alle variabili, alle funzioni, alle costanti e alle macro in modo appropriato
15
Naming conventions
Le naming conventions, o convenzioni di denominazione, si riferiscono alle regole e alle linee guida per la denominazione delle variabili, delle funzioni, delle costanti e delle macro all'interno di un programma. Le naming conventions sono importanti perché aiutano a rendere il codice facile da leggere, comprendere e mantenere, garantendo che i nomi siano descrittivi e coerenti.
Ci sono diverse tecniche per le naming conventions, alcune delle più comuni sono:
16
© FB - 01.2023
Naming conventions
Esistono anche altre convenzioni utilizzate in diversi contesti, come ad esempio il Hungarian Notation, una convenzione di denominazione che utilizza prefissi per indicare il tipo di una variabile.
Come per la struttura del codice, è importante che le naming conventions siano condivise e adottate dall'intera comunità di sviluppatori, in modo che tutti i membri del team di sviluppo siano allineati e che il codice sia scritto in modo coerente. Ciò aiuta a rendere il codice più facile da leggere e comprendere, e aumenta la qualità generale del progetto.
Inoltre è importante che le naming conventions siano flessibili e possano evolversi nel tempo, in modo che possano adattarsi alle esigenze del progetto e del team di sviluppo. È anche importante che le naming conventions siano documentate e spiegate ai nuovi sviluppatori in modo che possano comprendere le motivazioni dietro alle scelte di denominazione.
In sintesi, le naming conventions sono importanti perché aiutano a rendere il codice facile da leggere, comprendere e mantenere, garantendo che i nomi siano descrittivi e coerenti. Ciò aiuta a rendere il progetto più robusto e scalabile.
17
© FB - 01.2023
Indentazione e spaziatura
Come impostare l'indentazione e l'uso degli spazi per rendere il codice leggibile
18
Indentazione e spaziatura
L'indentazione e la spaziatura sono importanti perché aiutano a rendere il codice facile da leggere e comprendere. L'indentazione consiste nell'utilizzare spazi o tabulazioni per allineare il codice all'interno di un blocco di codice, mentre la spaziatura consiste nell'utilizzare spazi tra parole chiave, operatori e altri elementi del codice per migliorare la leggibilità.
Ci sono diverse tecniche per l'indentazione e l'uso degli spazi, alcune delle più comuni sono:
19
© FB - 01.2023
Indentazione e spaziatura
Per impostare l'indentazione e l'uso degli spazi, è possibile utilizzare l'editor di codice o il sistema di sviluppo integrato (IDE) che si sta utilizzando. La maggior parte degli editor di codice e degli IDE hanno opzioni per impostare l'indentazione e la spaziatura automatica, in modo che il codice venga formattato automaticamente in base alle impostazioni selezionate.
Inoltre, alcuni editor di codice e IDE forniscono anche plug-in o estensioni per aiutare nell'applicazione di specifiche convenzioni di codifica, come ad esempio lo standard di codifica del team o quello dell'intera comunità del linguaggio.
In sintesi, l'indentazione e la spaziatura sono importanti perché aiutano a rendere il codice facile da leggere e comprendere. È importante che l'indentazione e l'uso degli spazi siano coerenti all'interno di un progetto per garantire una maggiore leggibilità del codice e facilità di manutenzione. Gli editor di codice o gli IDE possono essere utilizzati per impostare e gestire l'indentazione e gli spazi automaticamente.
20
© FB - 01.2023
Indentazione del codice
Indentare correttamente il codice e usare sempre lo stesso stile.
�//Stile compatto
if(cond1) {
//codice�} else if(cond2) {
//codice�} elese {
//codice�}
//Stile esteso
if(cond1)
{
//codice�}
else if(cond2)
{
//codice�}
elese
{
//codice�}
21
© FB - 11.2021
Codice funzionante, ma senza indentazione
22
© FB - 07.2023
Commenti
Come inserire commenti nel codice in modo efficace e perché sono importanti
23
Commenti
I commenti sono delle annotazioni inserite nel codice per descrivere il funzionamento del codice stesso o per fornire informazioni supplementari. I commenti sono importanti perché consentono di rendere il codice più leggibile e comprensibile per gli altri sviluppatori e per chi dovrà manutenere il codice in futuro.
Ecco alcuni consigli per inserire commenti nel codice in modo efficace:
24
© FB - 01.2023
Commenti
25
© FB - 01.2023
Commenti
Scrivere i commenti prima di scrivere codice è una buona pratica di programmazione perché aiuta a chiarire gli obiettivi e le intenzioni del codice. In particolare, è utile scrivere i commenti prima di iniziare a scrivere il codice perché ti permette di pensare attentamente a ciò che vuoi fare e come lo vuoi fare.
I commenti presenti nei programmi saranno su vari livelli:
Scrivere cosa avete intenzione di fare seguendo quanto già scritto nei diagrammi è un'altra buona pratica di programmazione perché aiuta a mantenere una corrispondenza tra il codice e la progettazione. In particolare, seguendo quanto già scritto nei diagrammi, si ha una maggiore comprensione del funzionamento dell'algoritmo, si evitano errori e si rende più facile la manutenzione del codice.
26
© FB - 01.2023
Doxygen
La notazione Doxygen è uno standard per la documentazione del codice sorgente in molte lingue di programmazione, tra cui C. I commenti scritti in questo formato possono essere facilmente convertiti in documentazione online o in formato PDF.
/**
* @brief Calcola il massimo comune divisore tra due numeri
* utilizzando l'algoritmo di Euclide.
* @param a primo numero
* @param b secondo numero
* @return il massimo comune divisore tra a e b
*/
int mcd(int a, int b) {
// ... codice della funzione ...
}
In generale, la notazione Doxygen utilizza la notazione /** per iniziare un commento e */ per chiudere. Ogni riga all'interno del commento deve iniziare con @ seguito da un tag per descrivere il contenuto del commento (es. @param per descrivere un parametro, @return per descrivere il valore di ritorno, etc.).
27
© FB - 01.2023
Intestazione del progetto (main.c)
/** ****************************************************************************************
* \mainpage <nome del progetto>
*
* @brief <inserire una breve descrizione del progetto>
* <specifiche del progetto>
* <specifiche del collaudo>
*
* @author <autore>
* @version 1.0 <data> <Descrivere le modifiche apportate>
* @version 1.1 <data> <Descrivere le modifiche apportate>
*/
Elenco dei comandi disponibili
28
© FB - 10.2019
Intestazione dei moduli
/** ****************************************************************************************
* @file <nome del file.h>
* @brief <inserire una breve descrizione del modulo>
* <specifiche del progetto>
* <specifiche del collaudo>
*
* @author <autore>
* @version 1.0 <data> <Descrivere le modifiche apportate>
* @version 1.1 <data> <Descrivere le modifiche apportate>
*/
29
© FB - 10.2019
Intestazione delle routine
/** ****************************************************************************************
* @brief <inserire una breve descrizione della routine>
* @param <elenco dei parametri in ingresso alla funzione>
* @retval <valori restituiti>
* @see <See Also: Describes a cross-reference to classes, functions, methods, variables, ...>
*
* @author <autore>
* @version 1.0 <data> <Descrivere le modifiche apportate>
* @version 1.1 <data> <Descrivere le modifiche apportate>
*/
30
© FB - 10.2019
Documentazione
Come generare documentazione per il codice e perché è importante
31
Documentazione
La documentazione del codice è una parte importante dello sviluppo di software poiché consente di comprendere come funziona il codice e come utilizzarlo correttamente. La documentazione del codice può essere generata in diverse forme, come commenti nel codice, documenti di progetto o manuali d'uso.
Ci sono diverse ragioni per cui la documentazione del codice è importante:
32
© FB - 01.2023
Documentazione
Per generare la documentazione del codice, è possibile utilizzare diverse tecniche come ad esempio:
33
© FB - 01.2023
Documentazione
PIn sintesi la documentazione del codice è una parte importante dello sviluppo di software poiché consente di comprendere come funziona il codice e come utilizzarlo correttamente, facilitando la manutenzione e la modifica del codice in futuro, consente la collaborazione con altri sviluppatori e supporta la formazione di nuovi sviluppatori.
Inoltre, è importante che la documentazione sia aggiornata e mantenuta in sincronia con il codice sorgente. Ciò consente di assicurare che la documentazione sia sempre precisa e utile per chi legge il codice.
Inoltre è fondamentale seguire degli standard di documentazione come ad esempio il formato del commento, la lunghezza dei commenti o la formattazione.
In generale, la documentazione del codice è un'attività importante che richiede tempo e impegno, ma che alla fine può portare ad un codice più robusto, facile da gestire e comprendere.
34
© FB - 01.2023
Buone pratiche di programmazione
Come utilizzare le buone pratiche di programmazione per scrivere codice robusto e mantenibile
35
Buone pratiche di programmazione
Le buone pratiche di programmazione sono un insieme di regole e linee guida che aiutano gli sviluppatori a scrivere codice robusto e mantenibile. Queste pratiche si basano su anni di esperienza nel campo della programmazione e possono aiutare a prevenire problemi comuni come errori di programmazione, problemi di performance e problemi di manutenibilità.
Alcune delle buone pratiche di programmazione più comuni sono:
36
© FB - 01.2023
Buone pratiche di programmazione
In sintesi, utilizzando queste buone pratiche di programmazione, si può scrivere codice più robusto e mantenibile, riducendo il rischio di errori e problemi di performance, e rendendo il codice più facile da capire e mantenere.
37
© FB - 01.2023
Magic numbers
Un magic numbers è un numero utilizzato nel codice sorgente. È magico perché nessuno ha la più pallida idea di cosa significhi, incluso l'autore del codice passati tre mesi dalla sua scrittura.
Evitare quindi di utilizzare valori costanti all’interno del codice. Creare invece delle costanti con tali valori. In questo modo il nome della costante chiarirà a cosa serve e sarà più semplice modificarne successivamente il valore.
38
© FB - 11.2021
Magic numbers
Il concetto di "magic number" si riferisce ai valori costanti, come numeri interi o costanti simboliche, utilizzati nel codice senza una descrizione o una spiegazione del loro significato.
Il problema con i "magic number" è che possono rendere il codice difficile da capire e mantenere, in quanto non è immediatamente chiaro a cosa si riferiscano o perché sono stati utilizzati in quel modo.
Per questo motivo, si consiglia di evitare l'utilizzo di "magic number" e di sostituirli con costanti simboliche che descrivono chiaramente il loro significato. Queste costanti simboliche dovrebbero essere definite in un'area comune del codice, come un file di intestazione, in modo che siano facilmente accessibili e comprensibili per tutti gli sviluppatori che lavorano sul progetto.
In generale, l'utilizzo di "magic number" può essere evitato in vari modi:
39
© FB - 11.2021
ENUM
In C, le enumerazioni (o "enum" per brevità) sono una forma di tipo di dati che consente di assegnare nomi significativi a un insieme di valori costanti. In altre parole, un'enumerazione ti permette di creare un nuovo tipo di dati costituito da un insieme di valori pre-definiti.
Una definizione di enumerazione in C ha la seguente sintassi:
enum Stato {STATE_ERR, STATE_OPEN, STATE_RUNNING, STATE_DYING};
enum ErrType { ERR_NONE, ERR_FILE, ERR_NOTFOUND};
...
40
© FB - 11.2021
ENUM
enum giorni_settimana {
LUNEDI,
MARTEDI,
MERCOLEDI,
GIOVEDI,
VENERDI,
SABATO,
DOMENICA
};
Una volta definita una enumerazione, è possibile creare variabili di questo tipo e assegnare loro i valori dell'enumerazione:
enum giorni_settimana oggi, domani;
oggi = MERCOLEDI;
domani = GIOVEDI;
41
© FB - 11.2021
ENUM
Inoltre, si può anche assegnare un valore numerico ad un valore dell'enumerazione specificando un valore numerico prima del nome del valore:
enum giorni_settimana {
LUNEDI = 1,
MARTEDI,
MERCOLEDI,
GIOVEDI,
VENERDI,
SABATO,
DOMENICA
};
In questo modo LUNEDI avrà valore 1, MARTEDI valore 2 e così via.
In generale, le enumerazioni sono utilizzate per migliorare la leggibilità del codice e per evitare l'utilizzo di numeri magici. Inoltre aiuta anche a gestire meglio gli errori, perché è possibile utilizzare gli enumeratori come valori di ritorno per indicare se una funzione ha avuto successo o meno.
42
© FB - 11.2021
Error handling
Come gestire gli errori e le eccezioni in modo appropriato
43
Error handling
L'error handling è una parte importante dello sviluppo di software, poiché consente di gestire gli errori e le eccezioni che possono verificarsi durante l'esecuzione del codice. L'error handling consente di evitare che gli errori causino arresti anomali o danneggiamenti dei dati e di garantire che il software continui a funzionare in modo stabile e affidabile.
Ci sono diverse tecniche per gestire gli errori e le eccezioni in modo appropriato, alcune delle più comuni sono:
44
© FB - 01.2023
Error handling
In sintesi, l'error handling è una parte importante dello sviluppo di software, poiché consente di gestire gli errori e le eccezioni in modo appropriato per garantire che il software continui a funzionare in modo stabile e affidabile. Ci sono diverse tecniche per gestire gli errori e le eccezioni, come l'utilizzo di return codes, l'utilizzo di eccezioni, il logging degli errori e la gestione degli errori in fase di progettazione.
Go from working system to working system: collaudare sempre ogni porzione di codice scritto.
45
© FB - 01.2023
Collaudo
Quando troviamo un errore, dobbiamo risolverlo immediatamente, più a lungo rimandiamo la correzione e più complicato diventerà il sistema, rendendolo più difficile da ritrovare. Ricorda che i bug non se ne vanno via da soli e quando il sistema diventa più complesso i bug si manifesteranno in modo misterioso e inaspettato.
Per questo motivo, dovremmo testare completamente ogni modulo individualmente, prima di combinarlo con altri in un sistema più ampio. Non dovremmo aggiungere nuove funzionalità prima di essere sicuri che il sistema attuale sia privo di bug. Iniziamo con un sistema funzionante, aggiungiamo funzionalità, quindi eseguiamo il debug di questo sistema fino a farlo funzionare di nuovo. Questo approccio incrementale semplifica il monitoraggio dei progressi. Ci permette di annullare le decisioni che dimostrano sbagliate, perché possiamo sempre tornare al sistema di lavoro precedente. Aggiungere nuove funzionalità prima che il vecchio software sia sottoposto a debug è molto rischioso. Rimandare il controllo degli errori, ci permette facilmente di portare il progetto scadenza con il 100% delle funzionalità implementate, ma con un sistema che non funziona.
Viceversa, con l'approccio incrementale, quando la schedulazione del progetto slitta, saremo in grado, alla scadenza, di fornire un sistema funzionante che supporta alcune delle funzionalità.
46
© FB - 11.2021
Revisione del codice
Come effettuare la revisione del codice in modo efficiente e come implementare le linee guida dello standard di codifica.
47
Revisione del codice
La revisione del codice è il processo di esaminare il codice scritto da uno o più sviluppatori per individuare eventuali errori, problemi di qualità e opportunità di miglioramento. La revisione del codice è una pratica importante poiché consente di migliorare la qualità del codice, di individuare e correggere gli errori in modo tempestivo e di garantire che il codice segua gli standard e le linee guida del progetto.
Ecco alcuni consigli per effettuare la revisione del codice in modo efficiente:
48
© FB - 01.2023
Revisione del codice
In sintesi, la revisione del codice è un passo importante nello sviluppo di software, in quanto consente di individuare e correggere gli errori, migliorare la qualità del codice e garantire che il codice segua gli standard e le linee guida del progetto. Utilizzando un processo di revisione formale, strumenti di supporto, un formato di codice standard, una check-list, coinvolgendo più sviluppatori, un sistema di controllo di versione, un sistema di ticketing e un sistema di report, si può effettuare una revisione del codice efficiente ed efficace.
49
© FB - 01.2023
Esercitazioni
50
Approfondimenti
Nomi
E’ molto importante, nella scrittura del codice, un utilizzo attento dei nomi.
52
© FB - 11.2021
Commento di ampie parti di codice
Invece di commentare con /* e */ codice non più in uso, è possibile usare #if 0, usando però nomi descrittivi per le macro.��#define IS_DEBUG 0
void example() {
great looking code
#if IS_DEBUG
lots of code
#endif
more code
}
53
© FB - 11.2021
Grazie per l’attenzione
Link/Riferimenti
55
© FB - 01.2023
Revisioni
v1.0 13/01/23 - versione iniziale (da v1.0 11/09/21)