2012-03-30 3 views
10

Se una funzione ha un tipo di ritorno diverso da void, e la funzione non restituisce nulla, quindi suppongo che il compilatore restituisca un valore obsoleto (probabilmente visto come un valore non inizializzato). Succede al momento della compilazione, quindi perché non dovrebbe generare un errore?Se una funzione non restituisce alcun valore, con un tipo di ritorno valido, è giusto che il compilatore lanci la spazzatura?

Per esempio,

int func1() { 
    return; // error 
} 

int func2() { 
    // does not return anything 
} 

Il secondo func2 dovrebbe generare un errore, ma non è così. C'è una ragione per questo? Il mio pensiero era tale che, può essere visto come un valore non inizializzato, quindi se abbiamo bisogno di gettare un errore nel secondo caso, quindi abbiamo bisogno di gettare l'errore, se un valore è inizializzato, dire

int i; // error 
    int i = 6; // okay 

Qualsiasi pensieri, o si tratta di una domanda doppia? Apprezzo il vostro aiuto.

+2

C o C++? Ricevi errori o avvisi del compilatore? Quale compilatore stai usando? – littleadv

+1

Alzare gli avvisi. –

+0

possibile duplicato di [opzioni gcc: avviso su funzioni non vuote senza un'istruzione return] (http://stackoverflow.com/questions/9924570/gcc-options-warning-on-non-void-functions-without-a- dichiarazione di ritorno) –

risposta

15

In C++, tale codice è indefinito:

[stmt.return]/2 ... scorre l'estremità di una funzione è equivalente ad un rendimento senza valore; questo si traduce in un comportamento indefinito in una funzione di ritorno del valore. ...

La maggior parte dei compilatori genererà un avviso per codice simile a quello nella domanda.

Lo standard C++ non richiede che questo sia un errore di compilazione perché nel caso generale sarebbe molto difficile determinare correttamente se il codice viene effettivamente eseguito al termine della funzione o se la funzione viene chiusa tramite un'eccezione (o un meccanismo longjmp o simile).

consideri

int func3() { 
    func4(); 
} 

Se func4() tiri liberi, poi questo codice è totalmente bene. Il compilatore potrebbe non essere in grado di vedere la definizione di func4() (a causa della compilazione separata), e quindi non può sapere se lancerà o meno.

Inoltre, anche se il compilatore può provare che func4() non gira, dovrebbe comunque dimostrare che func3() viene effettivamente chiamato prima che possa legittimamente rifiutare il programma. Tale analisi richiede l'ispezione dell'intero programma, che è incompatibile con la compilazione separata e che non è nemmeno possibile nel caso generale.

+2

Molte lingue incluso C# e Java richiederebbero una istruzione 'return someValue;' nell'esempio precedente, anche se non potrebbe mai essere eseguito. La progettazione della lingua riguarda i compromessi e il valore relativo della diagnostica utile rispetto a un bisogno occasionale di codice stupido per placare un compilatore. Non sono d'accordo con molte delle decisioni di Java/C#, ma questa in particolare non mi interessa. – supercat

+1

@supercat: La mia risposta deve essere interpretata come: "C++ rende questo comportamento indefinito, ma sfortunatamente, questo non è abbastanza per i compilatori che effettivamente rifiutano questo codice, perché è impossibile (in fase di compilazione) rilevare (perfettamente) se o non si verifica il comportamento non definito effettivo. ". Ciò non vuol dire che sia impossibile progettare un linguaggio diverso che rifiuta prudentemente programmi che * potrebbero * essere validi ma che non si adattano al modello di sicurezza del sistema di tipi di quel linguaggio (che già C++, per altre cose) . – Mankarse

4

In C, è in effetti legale che una funzione non vuota termini senza restituire un valore, , a condizione che il codice chiamante non tenti di utilizzare il valore restituito.

D'altra parte una dichiarazione return senza un'espressione non può apparire in una funzione non vuota.

Le parti pertinenti dello standard C99 sono §6.9.1 per il primo caso:

Se il } che termina una funzione è raggiunto, e il valore della chiamata funzione viene utilizzata dal chiamante , il comportamento non è definito.

e §6.8.6.4 per il secondo caso:

Un return economico senza espressione sono visualizzati solo in una funzione cui tipo di ritorno è void.

+0

Il primo paragrafo è corretto per C, ma non per C++. –

+1

@KeithThompson: Ecco perché l'ho iniziato con "In C ..." – caf

+0

Non so come mi sia mancato. (Ma la domanda è stata codificata sia in C che in C++). –

2

Entrambe le funzioni sono mal formate. La differenza tra loro è che il tuo func1 viola le regole su come l'istruzione return può essere utilizzata mentre il tuo func2 è un comportamento non definito. L'istruzione return nel tuo func1 è illegale e un'implementazione deve diagnosticare questo. La mancanza di una dichiarazione di ritorno nel tuo func2 è un comportamento non definito. La maggior parte dei compilatori lo diagnosticano, ma nessuno deve farlo. comportamento

+0

In C, la prima funzione non è mal formata. Il comportamento non è definito se il chiamante tenta effettivamente di utilizzare il valore restituito. – caf

+0

Sì, sono d'accordo, questo è più di un test e stiamo cercando di scoprire perché il C commite abbia questo modo ... – howtechstuffworks

9

In C, citando N1256 6.9.1p12:

Se il } che termina una funzione è raggiunto, e il valore della chiamata funzione è utilizzato dal chiamante, il comportamento è indefinito.

Quindi è legale (ma una cattiva idea) per una funzione non-vuoto non riuscire a restituire un valore, ma se lo fa e il chiamante tenta di utilizzare il risultato, il comportamento è indefinito. Si noti che non restituisce necessariamente solo un valore arbitrario; per quanto riguarda lo standard, tutto è possibile.

Pre-ANSI C non ha avuto la parola chiave void, quindi il modo di scrivere una funzione che non ha restituito un valore è stato quello di omettere il tipo restituito, rendendolo implicitamente restituito int. Richiedere un'istruzione return in una funzione di ritorno del valore avrebbe danneggiato il vecchio codice. Avrebbe inoltre richiesto un'ulteriore analisi da parte del compilatore per determinare che tutti i percorsi di codice colpissero una dichiarazione return; tale analisi è ragionevole per i compilatori moderni, ma potrebbe essere stato un onere eccessivo quando C fu prima standardizzato.

C++ è leggermente più rigido. In C++:

scorre l'estremità di una funzione è equivalente a un ritorno con alcun valore; ciò comporta un comportamento non definito in una funzione di ritorno valore.

quindi il comportamento non è definito se il chiamante tenta di utilizzare il risultato (inesistente) o meno.

C e C++ compilatori certamente possono mettere in guardia circa mancante return dichiarazioni, o sui percorsi di controllo che cadono fuori alla fine di una funzione senza l'esecuzione di un'istruzione return, ma i rispettivi standard non richiedono loro di farlo.

+2

Tale analisi è ragionevole solo in casi semplici: in casi complessi, il compilatore potrebbe non disporre di informazioni sufficienti per sapere che rileverà sempre un'istruzione 'return'. – caf

+0

Sarebbe possibile richiedere che tutti i possibili percorsi di controllo eseguano un'istruzione 'return'; Penso che C# lo faccia. Ad esempio, '{if (1) {return 42; } else {puts ("Nessun ritorno qui"); } 'violerebbe tale requisito, anche se in realtà non è possibile evitare il' ritorno'. C e C++ semplicemente non lo fanno. –

+0

@Keith: È impossibile. Vedi la risposta di Mankarse. –

Problemi correlati