Gli incarichi nella condizione di condizionale sono una cattiva pratica?

33

Supponiamo di voler scrivere una funzione che concatena due stringhe in C. Il modo in cui scriverei è:

void concat(char s[], char t[]){
    int i = 0;
    int j = 0;

    while (s[i] != '
void concat(char s[], char t[]){
    int i, j;
    i = j = 0;
    while (s[i] != '
void concat(char s[], char t[]){
    int i = 0;
    int j = 0;

    while (s[i] != '
void concat(char s[], char t[]){
    int i, j;
    i = j = 0;
    while (s[i] != '%pre%') i++;

    while ((s[i++]=t[j++]) != '%pre%');

}
'){ i++; } while (t[j] != '%pre%'){ s[i] = t[j]; i++; j++; } s[i] = '%pre%'; }
') i++; while ((s[i++]=t[j++]) != '%pre%'); }
'){ i++; } while (t[j] != '%pre%'){ s[i] = t[j]; i++; j++; } s[i] = '%pre%'; }

Tuttavia, K & R nel loro libro l'hanno implementato in modo diverso, in particolare includendo tanto nella condizione parte del tempo loop il più possibile:

%pre%

Qual è il modo preferito? È incoraggiato o scoraggiato scrivere codice come fa K & R? Credo che la mia versione sarebbe più facile da leggere da altre persone.

    
posta Richard Smith 29.10.2016 - 20:53
fonte

8 risposte

79

Preferisci sempre la chiarezza all'intelligenza. In passato il miglior programmatore era quello il cui codice nessuno poteva capire. "Non riesco a dare un senso al suo codice, deve essere un genio" , hanno detto. Al giorno d'oggi il miglior programmatore è quello il cui codice chiunque può capire. Il tempo del computer è più economico ora del programmatore.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. (M. Fowler)

Quindi, no doudbt, opterei per l'opzione A. E questa è la mia risposta definitiva.

    
risposta data 29.10.2016 - 21:03
fonte
32

La regola d'oro, come nella risposta di Tulains Córdova, è assicurarsi di scrivere un codice comprensibile. Ma non sono d'accordo con la conclusione. Quella regola d'oro significa scrivere codice che il tipico programmatore che finirà per mantenere il tuo codice può capire. E tu sei il miglior giudice su chi sia il tipico programmatore che finirà per mantenere il tuo codice.

Per i programmatori che non hanno iniziato con C, la prima versione è probabilmente più facile da capire, per ragioni che già conosci.

Per quelli che sono cresciuti con quello stile di C, la seconda versione potrebbe essere più facile da capire: per loro, è ugualmente comprensibile ciò che fa il codice, per loro, lascia meno domande sul perché è scritto così com'è, e per loro, meno spazio verticale significa che più contesto può essere visualizzato sullo schermo.

Dovrai fare affidamento sul tuo buon senso. A quale pubblico vuoi rendere il tuo codice più facile da capire? Questo codice è scritto per un'azienda? Quindi il pubblico di destinazione è probabilmente gli altri programmatori di quella società. Si tratta di un progetto di hobby personale su cui nessuno lavorerà ma te stesso? Allora sei il tuo pubblico di destinazione. È questo codice che vuoi condividere con gli altri? Allora quegli altri sono il tuo pubblico di destinazione. Scegli la versione che corrisponde a quel pubblico. Sfortunatamente, non esiste un unico modo preferito per incoraggiare.

    
risposta data 30.10.2016 - 02:57
fonte
14

EDIT: la riga s[i] = '%code%'; è stata aggiunta alla prima versione, risolvendola così come descritto nella variante 1 di seguito, quindi questo non si applica più alla versione corrente del codice della domanda.

La seconda versione ha il vantaggio distintivo di essere correct , mentre il primo non lo è - non termina in modo corretto la stringa di destinazione.

Il "compito in condizione" consente di esprimere il concetto di "copia ogni carattere prima controllando il carattere null" in modo molto conciso e in un modo che rende l'ottimizzazione per il compilatore un po 'più semplice, sebbene molti software ingegneri in questi giorni trovano questo stile di codice meno leggibile. Se insisti a utilizzare la prima versione, dovresti scegliere

  1. aggiungi la terminazione nulla dopo la fine del secondo ciclo (aggiungendo altro codice, ma puoi obiettare che la leggibilità lo rende utile) o
  2. cambia il corpo del ciclo in "prima assegnazione, quindi verifica o salva il carattere assegnato, quindi aumenta gli indici". Controllare la condizione nel mezzo del loop significa rompere il loop (riducendo la chiarezza, disapprovato dalla maggior parte dei puristi). Salvare il char assegnato significherebbe introdurre una variabile temporanea (riducendo la chiarezza e l'efficienza). Entrambi quelli avrebbero annientato il vantaggio a mio parere.
risposta data 30.10.2016 - 13:21
fonte
6

Le risposte di Tulains Córdova e hvd coprono abbastanza bene gli aspetti di chiarezza / leggibilità. Consentitemi di inserire scoping come un'altra ragione a favore dei compiti in condizioni. Una variabile dichiarata nella condizione è disponibile solo nell'ambito della dichiarazione. Non è possibile utilizzare successivamente tale variabile per errore. Il ciclo per ha fatto questo per secoli. Ed è abbastanza importante che l'imminente C ++ 17 introduca una sintassi simile per se e interruttore :

if (int foo = bar(); foo > 42) {
    do_stuff();
}

foo = 23;   // compiler error: foo is not in scope
    
risposta data 30.10.2016 - 10:05
fonte
3

No. È molto standard e in stile C normale. Il tuo esempio è negativo, perché dovrebbe essere solo un ciclo for, ma in generale non c'è niente di sbagliato in

if ((a = f()) != NULL)
    ...

per esempio (o con while).

    
risposta data 29.10.2016 - 22:27
fonte
3

Nei giorni di K & R

  • "C" era il codice assembly portatile
  • È stato utilizzato dai programmatori che hanno pensato nel codice assembly
  • Il compilatore non ha fatto molta ottimizzazione
  • La maggior parte dei computer aveva "set di istruzioni complessi", ad esempio while ((s[i++]=t[j++]) != '{}') verrebbe mappato a un'istruzione sulla maggior parte delle CPU (mi aspetto il VAC dicembre)

Ci giorni

  • La maggior parte delle persone che leggono codice C non sono programmatori di codice assembly
  • I compilatori C fanno molta ottimizzazione, quindi è probabile che il codice più semplice da leggere sia tradotto nello stesso codice macchina.

(Una nota su usare sempre le parentesi graffe - il primo set di codice occupa più spazio a causa di alcuni "non necessari" %code% , nella mia esperienza questi spesso impediscono il codice che è stato mal combinato dal compilatore e consentono errori con errori ";" Posizionamenti da rilevare tramite strumenti.)

Tuttavia ai vecchi tempi avrebbe letto la seconda versione del codice. (Se ho capito bene!)

concat(char* s, char *t){      
    while (*s++);
    --s;
    while (*s++=*t++);
}
    
risposta data 31.10.2016 - 15:13
fonte
2

Anche riuscire a farlo è una pessima idea. È colloquialmente conosciuto come "The World's Last Bug", in questo modo:

if (alert = CODE_RED)
{
   launch_nukes();
}

Anche se non è probabile che tu commetta un errore che è abbastanza così grave, è molto facile rovinare accidentalmente e causare un errore difficile da trovare nella base di codice. I compilatori più moderni inseriranno un avviso per i compiti all'interno di un condizionale. Sono lì per un motivo, e faresti bene ad ascoltarli e ad evitare questo costrutto.

    
risposta data 31.10.2016 - 22:05
fonte
2

Entrambi gli stili sono ben formati, corretti e appropriati. Qual è più appropriato dipende in gran parte dalle linee guida di stile della tua azienda. Gli IDE moderni faciliteranno l'uso di entrambi gli stili attraverso l'uso del linting della sintassi live che evidenzia in modo esplicito le aree che altrimenti potrebbero diventare fonte di confusione.

Ad esempio, la seguente espressione è evidenziata da Netbeans :

if($a = someFunction())

sulla base di "assegnazione accidentale".

PerdireesplicitamenteaNetbeansche"sì, volevo davvero farlo ...", l'espressione può essere racchiusa in un insieme di parentesi.

if(($a = someFunction()))

Alla fine della giornata, tutto si riduce alle linee guida sullo stile aziendale e alla disponibilità di strumenti moderni per facilitare il processo di sviluppo.

    
risposta data 30.10.2016 - 05:39
fonte

Leggi altre domande sui tag