Perché utilizzare le nuove righe finali invece di guidare con printf?

77

Ho sentito che dovresti evitare di portare a capo una nuova riga quando usi printf . In questo modo, anziché printf("\nHello World!") dovresti usare printf("Hello World!\n")

In questo particolare esempio sopra non ha senso, poiché l'output sarebbe diverso, ma considera questo:

printf("Initializing");
init();
printf("\nProcessing");
process_data();
printf("\nExiting");

rispetto a:

printf("Initializing\n");
init();
printf("Processing\n");
process_data();
printf("Exiting");

Non riesco a vedere alcun beneficio con le nuove righe finali, tranne che sembra migliore. C'è qualche altra ragione?

EDIT:

I'll address the close votes here and now. I don't think this belong to Stack overflow, because this question is mainly about design. I would also say that although it may be opinions to this matter, Kilian Foth's answer and cmaster's answer proves that there are indeed very objective benefits with one approach.

    
posta Broman 19.11.2018 - 08:10
fonte

8 risposte

219

Una buona quantità di I / O del terminale è bufferizzata dalla linea , quindi terminando un messaggio con \ n puoi essere certo che verrà visualizzato in modo tempestivo. Con un comando \ n il messaggio può o non può essere visualizzato contemporaneamente. Spesso, questo significherebbe che ogni fase visualizza il messaggio di avanzamento del passaggio precedente , che non provoca alcuna fine di confusione e perdite di tempo quando si tenta di comprendere il comportamento di un programma.

    
risposta data 19.11.2018 - 08:17
fonte
71

Sui sistemi POSIX (fondamentalmente qualsiasi Linux, BSD, qualunque sia il sistema basato su open source che si possa trovare), una linea è definita come una stringa di caratteri terminata da una newline \n . Questa è l'ipotesi di base su cui si basano tutti gli strumenti della riga di comando standard, inclusi (ma non limitati a) wc , grep , sed , awk e vim . Questo è anche il motivo per cui alcuni editor (come vim ) aggiungono sempre un \n alla fine di un file e perché gli standard precedenti di C richiedevano intestazioni che terminavano con un carattere \n .

Btw: avere \n di linee terminate rende l'elaborazione del testo molto più semplice: sai per certo che hai una linea completa quando hai quel terminatore. E sai per certo che hai bisogno di guardare più caratteri se non hai ancora incontrato quel terminatore.

Naturalmente, questo è sul lato di input dei programmi, ma l'output del programma è molto spesso usato come input del programma di nuovo. Pertanto, il tuo output dovrebbe attenersi alla convenzione per consentire un input continuo in altri programmi.

    
risposta data 19.11.2018 - 14:31
fonte
31

Oltre a ciò che altri hanno menzionato, sento che c'è una ragione molto più semplice: è lo standard. Ogni volta che qualcosa stampa su STDOUT, quasi sempre si presume che sia già su una nuova riga, e quindi non ha bisogno di iniziarne una nuova. Presuppone anche che la riga successiva da scrivere agisca allo stesso modo, quindi termina utilmente con l'avvio di una nuova riga.

Se esporti linee di prima linea interleaved con linee di trailing-newline standard, "finirà per assomigliare a questo:

Trailing-newline-line
Trailing-newline-line

Leading-newline-line
Leading-newline-line
Leading-newline-lineTrailing-newline-line
Trailing-newline-line

Leading-newline-lineTrailing-newline-line
Trailing-newline-line
Trailing-newline-line

... che presumibilmente non è ciò che desideri.

Se si utilizzano solo nuove linee guida nel codice e lo si esegue solo in un IDE, potrebbe risultare corretto. Non appena lo esegui in un terminale o inserisci il codice di altre persone che scriverà in STDOUT insieme al tuo codice, vedrai un output indesiderato come sopra.

    
risposta data 19.11.2018 - 21:13
fonte
17

Poiché le risposte altamente votate hanno già fornito eccellenti motivi tecnici per cui dovrebbero essere preferiti i newline finali, mi avvicinerò da un altro punto di vista.

Nelle mie opinioni, i seguenti rendono un programma più leggibile:

  1. un elevato rapporto segnale / rumore (anche semplice ma non più semplice)
  2. le idee importanti vengono prima

Dai punti precedenti, possiamo affermare che le nuove righe finali sono migliori. I newline formattano il "rumore" rispetto al messaggio, il messaggio dovrebbe risaltare e quindi dovrebbe venire prima (l'evidenziazione della sintassi può anche aiutare).

    
risposta data 19.11.2018 - 21:42
fonte
16

L'utilizzo di nuove righe finali semplifica le modifiche successive.

Come esempio (molto banale) basato sul codice dell'OP, supponiamo di dover produrre un output prima del messaggio "Inizializzazione" e che l'output provenga da una parte logica diversa del codice, in un file sorgente diverso.

Quando esegui il primo test e trovi "Inizializzazione" viene ora aggiunto alla fine di una riga di qualche altro output, devi cercare attraverso il codice per trovare dove è stato stampato, e poi sperare di cambiare "Inizializzazione" in "\ nInizializzazione" non rovina il formato di qualcos'altro, in circostanze diverse.

Ora considera come gestire il fatto che il tuo nuovo output è in realtà opzionale, quindi la tua modifica a "\ nInizializzazione" a volte produce una riga vuota indesiderata all'inizio dell'output ...

Imposti un flag globale ( shock horror ?? !!! ) che dice se c'era un output precedente e testalo per stampare "Initializing" con un comando opzionale "\ n", o produci "\ n" insieme al tuo output precedente e lasci futuri lettori di codice a chiedersi perché questa "Inizializzazione" non non ha un "\ n" iniziale come tutti gli altri messaggi di output?

Se si generano costantemente righe nuove finali, nel punto in cui si sa di aver raggiunto la fine della riga che deve essere interrotta, si eliminano tutti questi problemi. Nota, che potrebbe richiedere un'istruzione puts ("\ n") separata alla fine di una logica che restituisce una riga pezzo per pezzo, ma il punto è che tu emetti la nel primo punto del codice dove sai devi farlo, non da qualche altra parte.

    
risposta data 19.11.2018 - 18:07
fonte
7

Why use trailing newlines instead of leading with printf?

Corrisponde strettamente alla specifica C

La libreria C definisce una riga come fine con un carattere di nuova riga '\n' .

A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined. C11 §7.21.2 2

Il codice che scrive i dati come linee corrisponderà a tale concetto della libreria.

printf("Initializing"); // Write part of a line
printf("\nProcessing"); // Finish prior line & write part of a line
printf("\nExiting");    // Finish prior line & write an implementation-defined last line

printf("Initializing\n");//Write a line 
printf("Processing\n");  //Write a line
printf("Exiting");       //Write an implementation-defined last line

Ri: l'ultima riga richiede un carattere di nuova riga che termina . Ti consiglio di scrivere sempre un '\n' finale sull'output e tollerarne l'assenza sull'input.

Controllo ortografico

Il mio correttore ortografico si lamenta. Forse anche tu lo fai.

  v---------v Not a valid word
"\nProcessing"

 v--------v OK
"Processing\n");
    
risposta data 21.11.2018 - 05:56
fonte
4

Le nuove linee guida possono spesso semplificare la scrittura del codice quando sono presenti condizioni, ad esempio

printf("Initializing");
if (jobName != null)
    printf(": %s", jobName);
init();
printf("\nProcessing");

(Ma come è stato notato altrove, potrebbe essere necessario svuotare il buffer di output prima di eseguire qualsiasi operazione che richiede molto tempo della CPU.)

Quindi può essere fatto un buon caso per entrambi i modi di farlo, anche se personalmente non mi piace printf () e userei una classe personalizzata per creare l'output.

    
risposta data 19.11.2018 - 14:09
fonte
2

Le nuove linee guida non funzionano bene con altre funzioni della libreria, in particolare puts() e perror nella Libreria standard, ma anche qualsiasi altra libreria che probabilmente utilizzerai.

Se vuoi stampare una linea pre-scritta (una costante o una già formattata, ad es. con sprintf() ), allora puts() è la scelta naturale (ed efficiente). Tuttavia, non c'è modo per puts() di terminare la riga precedente e scrivere una riga non terminata: scrive sempre il terminatore di riga.

    
risposta data 22.11.2018 - 00:24
fonte

Leggi altre domande sui tag