2015-09-23 11 views
6
Rückkehr

Mit gcc 5.2.0, bemerkte ich, dass dieser Code nicht eine Warnung generiert:Keine Warnung, wenn NULL mit gcc

#include <stddef.h> 

int function(void) 
{ 
    return NULL; 
} 

void procedure(void) 
{ 
    return NULL; 
} 

ich verwendet, um die Fahnen -Wall -Wextra -std=c99 -pedantic und ich bin mit archlinux. Ich bin nicht sicher, warum dieser Code auf gcc gut funktioniert, besonders seit clang 3.7.0 erzeugt eine Warnung.

Ich habe auch versucht mit älteren Versionen von gcc wie 4.9 oder 4.7 und sie beide generieren Warnungen.

Die Warnungen sind:

warning: return makes integer from pointer without a cast 

und

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

Ich sollte erwähnen, dass ich gcc 5.2 auf Debian kompilieren versucht, und das Ergebnis ist das gleiche. Also scheint Archlinux nicht das Problem zu sein.

Was ist der Grund? Ich kann nirgendwo anders etwas finden, was damit zusammenhängt.

Vielen Dank!

+1

möglich duplizieren http://stackoverflow.com/questions/1610030/why-can-you-return-from-a-non-void-function-without-returning-a-value-without-pr –

+0

Lol du meinst "invers duplizieren"? Mit dieser Frage wird gefragt, warum Sie einen Wert in einem Rumpf einer Void-Funktion zurückgeben können. Das "Duplikat" fragt, warum Sie einen Körper einer nicht-void-Funktion ohne eine return-Anweisung schreiben können. – BitTickler

+0

mögliches Duplikat von [Warum gibt 0x80000000 von einer Funktion, die int32 \ _t zurückgibt, keine Warnung zurück?] (Http://stackoverflow.com/questions/32656460/why-doesn-returning-0x80000000-from-a-function -that-returns-int32-t-cause-a-wa) –

Antwort

1

Die Gültigkeit der ersten Funktion hängt davon ab, wie NULL definiert ist. Es gibt kein Problem mit der ersten Funktion, wenn NULL als 0 definiert ist. Wenn es jedoch als (void *) 0 definiert ist (was normalerweise bei C-Code der Fall ist), wird die erste Funktion ungültig. GCC ist oft sehr permissiv gegenüber impliziten Pointer-zu-Integer-Konvertierungen.

Die zweite Funktion ist ungültig, ungültig. Die Sprachspezifikation besagt eindeutig, dass "eine return-Anweisung mit einem Ausdruck nicht in einer Funktion erscheinen soll, deren Rückgabetyp ungültig ist". Wenn es kompiliert, muss es ein weiteres Beispiel dafür sein, dass GCC über etwas zu großzügig ist.

Sie müssen GCC im -pedantic-Modus ausführen, wenn Sie möchten, dass der Diagnoseausgang der Standardsprache C entspricht. Im Standardmodus ist es kein glaubwürdiger C-Compiler (zumindest nicht in seiner Diagnoseausgabe) und die Tatsache, dass es "keine Warnung ausgibt" bedeutet absolut nichts.

In meinen Experimenten war ich nicht in der Lage, GCC zu beschweren über die zweite Funktion auch mit -std= und -pedantic Schalter. Es sieht wie ein Fehler im Compiler aus.

+0

OP behauptet, "-pedantic" zu verwenden. – juanchopanza

+0

Ich verwende tatsächlich '-pedantic'. – damwdan

3

Dies scheint eine Regression in gcc 5.2.0 zu sein - und, soweit ich das beurteilen kann, eine komische.

Mit gcc 4.4.5 und 4.8.4 erzeugt das Programm (nach dem Hinzufügen der erforderlichen #include <stddef.h>) Warnungen auf beiden return NULL;-Anweisungen, auch ohne zusätzliche Befehlszeilenoptionen.

Mit gcc 5.2.0 wird keine Warnung ausgegeben, auch nicht mit gcc -c -Wall -Wextra -std=c99 -pedantic. Für die zweite Funktion, die einen Wert aus einer void-Funktion zurückgibt, ist eine Diagnose erforderlich.

Jetzt ist hier der seltsame Teil.

$ 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 
$ 

Wenn USE_NULL definiert ist, werden keine Warnungen erzeugt.Das Kompilieren mit gcc -E -DUSE_NULL (das die Ausgabe des Präprozessors auf stdout druckt) bestätigt, dass NULL als ((void*)0) definiert ist. Aber wenn ich NULL durch ((void*)0) ersetze, werden die Warnungen erzeugt (wie sie sein sollten).

Ich weiß nicht, was los ist. Sobald das Makro NULL erweitert wurde, sollte es von ((void*)0) nicht zu unterscheiden sein, und doch ändert sich das Verhalten des Compilers je nachdem, welches verwendet wird.

+0

Sie meinen wahrscheinlich 5.2.0. –

+0

@AntoinePietri: Fest, danke! –