2015-05-14 18 views
10

Durante il debug del codice embedded, mi sono imbattuto in qualcosa di simile:MISRA Incremento in C

buffPtr = &a[5]; 
buffEndPtr = &a[10]; 

while (buffPtr != buffEndPtr) 
{ 
    *buffPtr = 0xFF; 
    buffPtr = &buffPtr[1];   /* MISRA improvement for: buffPtr++ */ 
} 

Perché questo costrutto un miglioramento rispetto (* buffPtr) ++?

+0

perché '(* buffPtr) ++' sarebbe sbagliato. Intendi '* buffPtr ++ = 0xFF;'? – mch

+2

@mch Immagino che sia un refuso nel corpo della domanda. guarda il commento nel codice. –

risposta

10

C'è una regola MISRA che indica che l'unica operazione matematica di puntatore consentita è l'indicizzazione.

Il modello che hai mostrato è un work around mal eseguito. È brutto/strano/non comune e probabilmente basato su un fraintendimento dello scopo di quella regola. Potrebbe anche violare un'altra regola.

Un modo migliore per scrivere questo codice sarebbe:

for(i=5; i < 10; i++) 
{ 
    a[i] = 0xff; 
} 

Aggiornamento 2015/05/20 - Dal momento che questa è stata la risposta accettata ecco la regola attuale violata, per gentile concessione di embedded.kyle:

MISRA-C: 2004, regola 17.4 (obbligatorio) o MISRA-C: 2012, regola 18.4 (obbligatorio) L'indicizzazione delle matrici è l'unica forma consentita di aritmetica del puntatore.

+0

Il codice originale è sicuramente un "work-around" delle regole, non un "miglioramento" a causa loro. Il ciclo for è il modello giusto. – AShelly

+0

Sì, vieni a pensarci, immagino che 'memset' non sia nemmeno MISRA conforme. Quindi, anche nei casi in cui funzionerà, non è il modo giusto per MISRA. Correzione –

9

La regola che (*buffPtr)++ sta violando è:

MISRA-C: 2004, regola 17.4 (obbligatorio) o MISRA-C: 2012, la Regola 18.4 (Obbligatorio)

Array indicizzazione deve essere l'unica forma consentita di puntatore aritmetico.

loro ragionamento dietro questa regola:

Array indicizzazione utilizzando la sintassi indice di matrice, ptr[expr], è la forma preferita di puntatori perché è spesso più chiara e quindi meno soggetto a errori di manipolazione dei puntatori . Qualsiasi valore di puntatore calcolato esplicitamente, , ha il potenziale per accedere agli indirizzi di memoria non validi o non validi. Tale comportamento è anche possibile con l'indicizzazione dell'array , ma la sintassi del pedice può facilitare l'attività di revisione manuale.

aritmetica dei puntatori in C può confondere il novizio L'espressione ptr+1 può essere erroneamente interpretata come l'aggiunta di 1 all'indirizzo tenutasi a ptr. In effetti, il nuovo indirizzo di memoria dipende dalla dimensione in byte della destinazione del puntatore. Questo malinteso può portare a un comportamento imprevisto se sizeof viene applicato in modo errato.

Molte delle regole MISRA hanno razionalizzazioni simili. Fondamentalmente il loro processo di pensiero è che se si scrive in modo semplicistico ed esplicito il più possibile, il codice sarà più leggibile e mantenibile, il che porterebbe quindi a un codice intrinsecamente più sicuro. Il codice più sicuro è lo scopo dietro lo standard MISRA.

Come ha sottolineato Brian, ci sono modi per scrivere codice che sono conformi a MISRA ma che violano ancora l'intenzione alla base della regola.L'esempio del ciclo for di Brian sarebbe il costrutto più comune e facilmente comprensibile a mio parere.

+1

: MISRA-C: 2012 consente ++ ma non +. È diverso e più rilassato rispetto alla regola citata in MISRA-C: 2004. – Lundin

5

In MISRA-C: regola del 2004 17.4 esisteva una regola di consulenza che vieta tutte le forme di aritmetica dei puntatori. L'intento era buono, lo scopo della norma è stato un tentativo di bandire codice potenzialmente pericoloso come ad esempio:

stuff* p; 
p = p + 5; // 5 stuff, not 5 bytes, bug or intentional? 

e da leggere difficile codice come

*(p + 5) = something; // harder to read but equivalent to p[5] 

In generale, l'intenzione è quella di consigliamo di utilizzare un iteratore intero anziché l'aritmetica del puntatore, quando si esegue il looping dei dati puntati.

Tuttavia, la regola ha anche vietato varie operazioni fondamentali del puntatore che probabilmente non sono pericolose, ad esempio ptr++. In generale, la regola era troppo severa.

In MISRA-C: 2012 questa regola (18.4) era rilassata per vietare solo gli operatori + - += -=.


Nel tuo caso, il buffPtr = &buffPtr[1]; era un maldestro tentativo di schivare regola 17.4, poiché la regola non ha molto senso. Invece il programmatore ha deciso di offuscare il loro programma, rendendolo meno leggibile e quindi meno sicuro.

Il modo corretto per risolvere questo problema è utilizzare l'operatore ++ e ignorare la regola 17.4. È una regola di consulenza, quindi non è necessario fare alcuna deviazione (a meno che l'implementazione locale di MISRA-C non indichi diversamente). Se hai bisogno di deviare, potresti semplicemente dire che la regola non ha alcun senso per l'operatore ++ e quindi fare riferimento a MISRA-C: 2012 18.4.

(Naturalmente, riscrivere l'intero ciclo per un ciclo for come mostrato in un'altra risposta è la migliore soluzione)

programmazione senza usare senso comune è sempre molto pericoloso, come è seguire ciecamente MISRA senza comprendere la logica suono dietro le regole, o in questo caso la mancanza di tali.

+0

Avevo giudicato l'intenzione della regola di richiedere che tutti gli oggetti puntatore identifichino l'inizio di un'allocazione, che è una limitazione semantica in altri linguaggi (come Pascal standard). Un dialetto di C con una tale limitazione semantica non sarebbe in grado di fare tutto ciò che può essere fatto in C, ma un'implementazione di tale dialetto potrebbe supportare il controllo degli array in modi che non sono possibili in C "full-powered" Avere il controllo dei limiti dell'array supportato dal compilatore può essere utile in alcuni tipi di sistemi che devono essere sicuri. – supercat