2015-09-23 18 views
6

Utilizzando gcc 5.2.0, ho notato che questo codice non genera un avvertimento:Nessun avviso al ritorno NULL con gcc

#include <stddef.h> 

int function(void) 
{ 
    return NULL; 
} 

void procedure(void) 
{ 
    return NULL; 
} 

ho usato le bandiere -Wall -Wextra -std=c99 -pedantic e sono in esecuzione Archlinux. Non sono sicuro del motivo per cui questo codice funzioni correttamente su gcc, soprattutto dal momento che clang 3.7.0 genera un avviso.

Ho anche provato con le versioni precedenti di gcc come 4.9 o 4.7 e entrambi generano avvisi.

Le avvertenze sono:

warning: return makes integer from pointer without a cast 

e

warning: ‘return’ with a value, in function returning void 

Devo dire che ho provato la compilazione gcc 5.2 su Debian e il risultato è lo stesso. Quindi archlinux non sembra essere il problema.

Qual è la logica? Non riesco a trovare nulla di simile a questo altrove.

Grazie!

+1

possibile duplicato http://stackoverflow.com/questions/1610030/why-can-you-return-from-a-non-void-function-without-returning-a-value-without-pr –

+0

Lol you mean "duplicato inverso"? Questa domanda ti chiede perché puoi restituire un valore in un corpo di una funzione di vuoto. Il "duplicato" chiede perché è possibile scrivere un corpo di una funzione non vuoto senza un'istruzione di ritorno. – BitTickler

+0

possibile duplicato di [Perché non restituisce 0x80000000 da una funzione che restituisce int32 \ _t causa un avviso?] (Http://stackoverflow.com/questions/32656460/why-doesnt-returning-0x80000000-from-a-function -that-returns-int32-t-causa-a-wa) –

risposta

1

La validità della prima funzione dipende dal modo in cui è definito NULL. Non c'è alcun problema con la prima funzione se NULL è definito come 0. Ma se capita di essere definito come (void *) 0 (che è normalmente il caso nel codice C), la prima funzione diventa non valida. GCC è spesso molto permissivo sulle conversioni implicite da puntatore a intero.

La seconda funzione non è valida. La specifica del linguaggio afferma chiaramente che "Una dichiarazione di reso con un'espressione non deve apparire in una funzione il cui tipo di reso è nullo." Se compila, deve essere un altro esempio di GCC che è eccessivamente permissivo su qualcosa.

È necessario eseguire GCC nella modalità -pedantic se si desidera che il relativo output diagnostico sia correlato al linguaggio C standard. In modalità predefinita non è un compilatore C credibile (almeno nelle versioni termiche del suo output diagnostico) e il fatto che "non emette un avviso" significa assolutamente nulla.

Eppure nei miei esperimenti non ero in grado di far lamentare GCC sulla seconda funzione anche con gli switch -std= e -pedantic. Sembra un bug nel compilatore.

+0

L'OP afferma di usare '-pedantic'. – juanchopanza

+0

Sto davvero usando '-pedantic'. – damwdan

3

Questa sembra essere una regressione in gcc 5.2.0 - e, per quanto posso dire, uno strano.

Con gcc 4.4.5 e 4.8.4, il programma (dopo aver aggiunto il numero richiesto #include <stddef.h>) genera avvisi su entrambe le istruzioni return NULL;, anche senza opzioni di riga di comando aggiuntive.

Con gcc 5.2.0, non viene generato alcun avviso, anche con gcc -c -Wall -Wextra -std=c99 -pedantic. Per il secondo, che restituisce un valore da una funzione void, è necessaria una diagnostica.

Ora ecco la parte strana.

$ gcc --version | head -n 1 
gcc (GCC) 5.2.0 
$ cat c.c 
#include <stddef.h> 

int function(void) { 
#ifdef USE_NULL 
    return NULL; 
#else 
    return ((void*)0); 
#endif 
} 

void procedure(void) { 
#ifdef USE_NULL 
    return NULL; 
#else 
    return ((void*)0); 
#endif 
} 
$ gcc -c c.c 
c.c: In function ‘function’: 
c.c:7:12: warning: return makes integer from pointer without a cast [-Wint-conversion] 
    return ((void*)0); 
      ^
c.c: In function ‘procedure’: 
c.c:15:12: warning: ‘return’ with a value, in function returning void 
    return ((void*)0); 
      ^
$ gcc -c -DUSE_NULL c.c 
$ 

Quando USE_NULL è definito, nessun avviso sono prodotti.La compilazione con gcc -E -DUSE_NULL (che stampa l'output del preprocessore su stdout) conferma che NULL è definito come ((void*)0). Ma quando sostituisco NULL con ((void*)0), gli avvisi sono prodotti (come dovrebbero essere).

Non so cosa sta succedendo. Una volta che la macro NULL è stata espansa, dovrebbe essere indistinguibile da ((void*)0), e tuttavia il comportamento del compilatore cambia a seconda di quale viene utilizzato.

+0

Probabilmente intendi 5.2.0. –

+0

@AntoinePietri: risolto, grazie! –