Devo usare la parentesi attorno a tutti gli operatori?

-1

I fatti

Questa è una domanda molto simile a questo , ma qui sto parlando di un caso più generale della regola MISRA-C3 5.0.2 o SEI CERT C EXP00-C (più permissivo).

All'interno di MISRA-C3 I deve utilizzare le parentesi per evitare la precedenza implicita dell'operatore. Quindi il seguente codice è corretto, ma ai miei occhi è molto semplice:

 if ((((x * y) + 3) > z) && ((w - 1) <= (42 + (x / (y + z)))))

Nota: mentre stavo scrivendo questa espressione ho dovuto copiarlo / incollarlo nel mio editor di codice per correggere la parentesi mancante perché troppo ingombrante.

Come programmatore esperto userei solo la parentesi per una precedenza non ovvia che potrebbe dipendere dal linguaggio di programmazione che uso. La tabella di precedenza dell'operatore C potrebbe non essere facile da imparare, soprattutto per i nuovi programmatori C e talvolta anche per i miei me stesso quando sono stanco di ore di programmazione nel bel mezzo della notte.

La mia regola empirica è:

Parenthesis shall be used for explicit operator precedence with all operators except the logical and (&&) and or (||), and the 4 basic operations (* / + -).

L'espressione sopra può quindi essere semplificata in questo modo:

 if ((x * y + 3) > z && (w - 1) <= (42 + x / (y + z)))

Quest'ultima espressione sembra molto più facile da leggere e posso vedere a colpo d'occhio se mi manca una parentesi.

Inoltre, poiché l'operatore uguale ( = ) rientra anche nella regola MISRA. Gli sviluppatori dovrebbero anche scrivere z = (a * b) e non z = a * b .

La storia dietro

Lavoro in un'azienda in cui gli sviluppatori sono lontani dall'esperienza nella programmazione in C nonostante tutti facciano programmi in C per oltre 10-15 anni. Continuano ad aggiungere commenti inutili x = 2; // Assign x with 2 ovunque e afferma che la prima espressione che ho scritto è molto più leggibile perché nessun essere umano può imparare a memoria la precedenza degli operatori. Di solito usano commenti, parentesi o dichiarazioni avanzate ovunque piuttosto che usare il loro buon senso per mantenere il flusso di lettura chiaro e comprensibile.

Stavo cercando di insegnare loro la bellezza della programmazione in cui il programmatore deve raccontare una storia e mantenere il flusso cristallino evitando cose inutili che mettono ovunque perché una volta qualcuno gli ha detto di farlo.

Oggi mi sto interrogando e mi chiedo se ho ragione o torto su questa cosa da parentesi. Forse la prima espressione è più comprensibile della seconda per la maggior parte delle persone.

Esempi

if ((i > LENGTH) && (((a * b) + c) > (d + e)))  // Bad
if (i > LENGTH && a * b + c > d + e)  // Good

y = ((x * y) + 1);  // Bad
y = x * y + 1;  // Good

La domanda

La mia regola empirica (riquadro giallo sopra) è una buona regola? La regola 5.0.2 di MISRA C3 è solo di consulenza e CERT-C è più nella mia direzione.

    
posta nowox 04.03.2018 - 12:30
fonte

2 risposte

10

Se hai bisogno di seguire alcuni standard, segui questo standard anche se il consiglio sembra non ottimale. Si noti che molti standard e linee guida di codifica hanno in mente un obiettivo specifico. MISRA è orientata verso la sicurezza e, pertanto, vuole eliminare ogni possibile costrutto confuso. Poiché la precedenza degli operatori a volte può essere confusa anche da programmatori esperti, la parentesi esplicita delle espressioni è in linea con tale obiettivo.

Per le convenzioni di codifica all'interno della tua organizzazione, l'obiettivo probabilmente non è un codice elegante e bello, ma la manutenibilità di tutti i programmatori. Le convenzioni di codifica dovrebbero essere orientate all'estremità inferiore della distribuzione delle competenze nella tua squadra. Questo è fondamentalmente lo stesso problema della recente domanda È corretto usare la meta-programmazione? . Quindi non fare ciò che è carino nei tuoi occhi, fai ciò che è compreso da tutti i membri del team.

Tieni presente che tutti i frammenti di codice sono un'arma rossa. Vorrei contrassegnare la maggior parte dei tuoi esempi in una revisione del codice. Non perché fanno o non usano parentesi, ma perché queste espressioni sono terribilmente complesse. L'intero problema di parentesi è molto meno urgente se estrai sottoespressioni come variabili separate. Come ulteriore vantaggio, questi nomi di variabili possono rendere il codice più auto-documentante. Anche se nessun altro lo fa, puoi usare tali tecniche per migliorare il codice che scrivi.

    
risposta data 04.03.2018 - 12:57
fonte
5

Bene, scriverò il tuo esempio quasi esattamente come hai detto è il "cattivo modo", perché non lo sto scrivendo per me, lo sto scrivendo per il prossimo (i) ingegnere (i), e potrebbero non avere la comprensione della funzionalità è ridotta quanto me.

Prendiamo il secondo (semplice) esempio nel tuo ultimo blocco di codice:

y = ((x * y) + 1);  // Some valuable comment here or maybe no comment at all

Questo rende la persona che legge il codice (e possibilmente cambiandolo) a capire che sto impostando y sull'incremento del prodotto, rispetto al prodotto dell'incremento. Per me, quando ho letto il codice scritto da qualcuno anni fa e sto cercando di capire cosa sta succedendo, questa versione mi fa vedere rapidamente che il prodotto viene incrementato.

y = x * y + 1;  // Possibly some useless comment

La mia lettura iniziale rapida, a malapena (perché ho fretta, non capisco bene il codice, e voglio davvero tornare allo sviluppo YouTube potrebbe non arrivare che il prodotto viene incrementato, specialmente se il commento è un po 'vago. Ora devo interrompere la mia lettura a malapena e pensare a:

  1. Cosa volevano fare
  2. Cosa hanno fatto veramente
  3. Cosa potrebbe accadere se non facessero ciò che desideravano

Parentesi esplicite? Personalmente li amo quando scrivo e li amo quando leggo. Una cosa che faccio è usare le variabili temporanee e lo spazio bianco a mio vantaggio in modo che sia più facile da leggere.

Prendendo il primo esempio:

if ((((x * y) + 3) > z) && ((w - 1) <= (42 + (x / (y + z)))))

Scriverò come (se non volessi usare le variabili temporanee):

if (   (((xDim * yDim) + PROD_OFFSET) > zVolume)
    && ((wDim - EDGE_FACTOR) <= (MAX_THRESH + (xDim  / (yDim + zVolume)))))
{
...
}

Ora è più facile per me vedere che ci sono due (2) condizionali che devono essere soddisfatti (ora ognuno sulla propria linea) e le mie variabili e costanti ora hanno un po 'più senso. (So che i nomi variabili e costanti erano casuali per il tuo esempio, ma volevo mostrare un confronto completo.)

Parentesi / parentesi graffa? I buoni IDE (con LINT integrato) ti consentono sempre di sapere in anticipo.

    
risposta data 22.03.2018 - 00:06
fonte

Leggi altre domande sui tag