A parte la 2 e la 9 (che dovrei seguire piu’ spesso, ma a volte non si puo’ smontare mezzo codice solo per una questione di stile), le ho sempre seguite tutte. Ora mando il cv alla NASA 😀
Vabbé, però la 2 e la 3 vanno benissimo se devi scrivere il controllo di un razzo (o di una lavatrice, il concetto è lo stesso) ma per il software applicativo sono il maleh.
E per la 9: ma allora perché cazzo scrivere in C? 🙂
Infatti io scrivo piu che altro software per ambienti realtime 🙂
La 9 e’ semplice buon senso. Non il fatto di non usare puntatori, ovviamente, ma di non usarli in modo complesso. Ci possono essere funzioni che prendono puntatori a puntatore, oppure anche qualche puntatore a funzione occasionalmente (specie quando devi scrivere codice estensibile in futuro con funzioni che ancora non conosci), ma senza esagerare, diciamo. Puntatori usati in modo complesso aumentano la probabilita’ di fare casino, e i tempi di debug.
La piu’ importante comunque, penso sia la 3. Le malloc, se posso, cerco di evitarle sempre. Uso quasi sempre allocazione statica, con strutture a dimensione
prefissata (con la dimensione in una define o una variabile const, per
espandere le strutture quando serve senza toccare il codice). Il che ti
rende semplice anche a usare for a
dimensione fissa, invece di while (che era la cosa del punto 2, pero’
qualcuno scappa sempre, se non cerchi esplicitamente di evitarlo).
In
ambito realtime la malloc puo’ causare problemi, specialmente quando
hai piu’ processi a priorita’ diverse con piu’ thread, e rendere la
ciclicita’ dei processi realtime impredicibile.
Esempio:
il thread A a bassa priorita’ inizia una malloc (ed entra nella sezione
critica). Poi, prima che la malloc sia finita, arriva un cambio di
contesto che switcha su un thread B ad alta priorita’. B cerca anche lui
di fare una malloc, ma NON PUO’ entrare nella sezione critica perche’
c’e’ la malloc di A ancora in corso. Per cui B SI BLOCCA, eleva A alla
sua stessa priorita’, e aspetta che finisca la propria malloc. Poi abbassa di nuovo
la priorita’ di A (e qua dipende dallo scheduler e dal kernel che
stiamo usando, alcuni non la abbassano nemmeno).
Ci
sono situazioni in cui i thread realtime NON POSSONO bloccarsi.
Immagina ad esempio un thread che calcola continuamente la posizione da
inviare a un motore con un clock di 1 millisecondo. Se si blocca, per un
ciclo la posizione non viene ricalcolata, e al motore rimane la stessa del ciclo
precedente. Il che significa che deve restare fermo. Se ipotizziamo che il motore sta girando a 500 metri
al secondo, significa una decelerazione da 500m/s a 0 in 1 ms, quasi
istantanea. Una botta mostruosa in grado di spaccare la macchina.
Tutto per una malloc 🙂
Situazioni analoghe si verificano anche in altri ambiti realtime: la diagnostica di un treno, il sistema di guida di di una sonda spaziale, il driver di una stampante, ecc, il tracker di un telescopio, il meccanismo di coordinamento dei motori di una nave, ecc…
Oltre
a cio’, le malloc sono lente, ti costringono a ricordarti sempre le
free, a stare attenti alla dimensione allocata, a usare poi tool per la
ricerca di memory leak, ecc. E’ facile fare casino, e difficile da vedere in debug poi.
Con
questo non dico che non si puo’ MAI usare eh. Dipende dalle situazioni,
vanno usate con cognizione di causa. Pero’ in genere, se posso evito.