2013-05-06 25 views
12

Ho acquistato questo libro chiamato "Scrittura di codice solido".Informazioni su "NULL" in questo specifico codice

Nel primo capitolo, c'è questo codice:

while(*pchTo++ = *pchFrom++) 
    NULL; 

Io davvero non capisco che cosa NULL fa in quel ciclo.

+1

Separa il punto e virgola dalla condizione del ciclo. (È un codice morto.) –

+21

E un tale libro si chiama "Scrivere codice solido"? – duDE

+11

Se questa pratica è desiderabile è aperta al dibattito, ma un libro che usa tale costrutto senza dedicare almeno un breve paragrafo a spiegare la motivazione mi sembra un buon libro ... –

risposta

3

Quel ciclo copia una stringa. Lo NULL è lì solo per fornire un corpo del loop.

+2

Questo è solo così confuso ... soprattutto per un libro di riferimento. Avrebbe potuto semplicemente lasciare il corpo mentre era vuoto con due parentesi graffe: 'while (...) {}'. O anche fare la cosa reale: 'while (* pchFrom) {* pchTo ++ = * pchFrom ++; } '. Questo è molto più chiaro .. – Gui13

+1

@xgbi: Questo non copia il terminatore null. – Joren

+0

Wooops, lascerò che il lettore risolva questo problema ... – Gui13

6

L'autore avrebbe potuto scrivere un ciclo completamente vuoto while proprio come è possibile scrivere un ciclo for senza corpo. Ciò avrebbe guardato come:

while (*pchTo++ = *pchFrom++); 

/* or */ 

while (*pchTo++ = *pchFrom++) 
    ; 

Entrambi i quali potrebbero cercare di confusione per alcune persone così hanno aggiunto il NULL per dare un corpo e renderlo meno confusione.

Modifica

Nota si può fare lo stesso con un ciclo for:

for (head = list->head; head->next; head = head->next); 
/* or */ 
for (head = list->head; head->next; head = head->next) 
    ; 
/* or */ 
for (head = list->head; head->next; head = head->next) 
    NULL; 

E tutto ciò che faremo è attraversare una lista andando all'elemento successivo mentre l'elemento successivo non è NULL

+3

Non vedo come sia "meno confuso".Avere un'espressione il cui valore non è utilizzato e che non ha effetti collaterali sembra molto più confuso. Le mie prove? Il fatto che OP ha dovuto fare questa domanda. –

+0

È meno confuso per le persone che si aspettano un corpo e non hanno mai visto un loop senza uno, o almeno immagino che sia il motivo per cui è stato inserito il 'NULL'. Mi sembra davvero brutto e quando ho un oggetto list (come sopra) che non ha un membro 'tail', di solito ho una funzione che usa il ciclo for che ho dimostrato sopra solo per averlo. In una nota editoriale: le persone che non includono un membro 'tail' nella loro struttura dovrebbero davvero riconsiderare il loro design. –

+0

Chiunque (intenzionalmente) mette un ';' nella stessa riga di una frase 'for' o' while' merita (almeno) una solida botta in testa. [La risposta di Keith] (http://stackoverflow.com/a/16401457/1711796) tocca brevemente la possibile confusione. In una nota a margine, un'altra opzione che molte persone preferiscono usa le parentesi graffe ('{}') in una forma o nell'altra. – Dukeling

2

Questo costrutto fornisce un buon modo per posizionare un punto di interruzione quando si lavora con un debugger. Alcuni IDE non mi hanno permesso di piazzare un breakpoint su un loop e avevo loop con corpi vuoti. Se si dispone di un'istruzione nel proprio corpo del ciclo, è più facile posizionare un punto di interruzione su di esso, anche se tale istruzione è inutile.

Altrimenti, come è già stato detto, dovrebbe fare esattamente la stessa cosa di un corpo con un corpo vuoto.

3

è probabile ispirato dalla sintassi della dichiarazione nulla di Ada:

while condition loop 
    null; 
end loop; 

Ada utilizza la parola chiave null sia per la costante puntatore nullo e per l'istruzione nulla (e poche altre cose).

Ha alcuni vantaggi rispetto all'istruzione Null di C, che è solo un punto e virgola. In particolare, è molto più esplicito. Un errore abbastanza comune nel codice C è quello di inserire una dichiarazione accidentale nullo aggiungendo una virgola, in particolare tra inesperti programmatori C che non hanno ancora elaborati dove virgola sono necessari e dove non sono:

while (condition); 
{ 
    /* statements */ 
} 

Senza il punto e virgola, le istruzioni sono controllate dal ciclo while. Con esso, il corpo del ciclo while è vuoto e il loop è probabilmente infinito se la condizione non ha effetti collaterali.

D'altra parte, se si desidera veramente un'istruzione nulla, l'uso di un punto e virgola può lasciare il lettore a chiedersi se qualcosa è stato ignorato involontariamente.

In C, NULL è una macro che si espande a una costante di puntatore nullo definita dall'implementazione.L'autore sta usando qui:

while(*pchTo++ = *pchFrom++) 
    NULL; 

come una sorta di dichiarazione di nulla - che funziona in realtà, perché l'espressione seguita da un punto e virgola è un'espressione dichiarazione in cui la dichiarazione viene valutata per i suoi effetti collaterali. Dal momento che non ha effetti collaterali, non fa nulla; si comporta proprio come una dichiarazione nulla vero:

while(*pchTo++ = *pchFrom++) 
    ; 

altra forma equivalente:

while(*pchTo++ = *pchFrom++) 
    42; 

A mio parere, questo è ben inteso, ma una cattiva idea. È facilmente riconoscibile per quei pochi di noi che hanno familiarità con C e Ada, ma i programmatori C più esperti la guarderanno e si chiederanno cosa diavolo ci fa la costante del puntatore nullo.

Non è abbastanza così male come la definizione di un insieme di macro per rendere aspetto C come la sintassi di un'altra lingua:

#define IF if (
#define THEN) 
#define BEGIN { 
#define END } 
#define ELSE } else { 

ma è con lo stesso spirito.

Il mio consiglio: non fare questo genere di cose. Se vuoi che il tuo codice C sia facilmente comprensibile dai lettori che conoscono C, scrivi un codice C idiomatico; non inventare trucchi intelligenti per far sembrare qualcos'altro. Le dichiarazioni nulle possono essere fonte di confusione, portando il lettore a chiedersi se qualcosa è stato lasciato fuori per caso. La migliore soluzione che, IMHO, è di utilizzare un commento:

while(*pchTo++ = *pchFrom++) { 
    /* empty body */ 
} 
+1

Trovo 'while (* pchTo ++ = * pchFrom ++) {}' ugualmente chiaro. Il blocco vuoto senza nemmeno lo spazio per mettere qualcosa lì segnala "non fare nulla" è intenzionale. –