MSVC hat kein Problem mit diesem Programm, aber gcc tut (mindestens gcc 4.6.1). Es gibt die folgenden Warnungen aus:
test.c: In function 'main':
test.c:3:9: warning: conflicting types for built-in function 'exit' [enabled by default]
test.c:4:22: warning: function called through a non-compatible type [enabled by default]
test.c:4:22: note: if this code is reached, the program will abort
Und wie versprochen, stürzt es ab, wenn es ausgeführt wird.Der Absturz ist kein Zufall bei einer inkorrekten Aufrufkonvention oder etwas - gcc erzeugt tatsächlich eine undefinierte Anweisung mit dem Opcode 0x0b0f, um explizit einen Absturz zu erzwingen (gdb zerlegt es als ud2
- Ich habe nicht nachgeschaut, was das CPU - Handbuch dazu sagen könnte opcode):
main:
.LFB0:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
.value 0x0b0f
.cfi_endproc
ich bin nur ungern, dass gcc ist dabei die falsch zu sagen, denn ich bin sicher, die Leute, die diese Compiler schreiben viel mehr über C wissen als ich. Aber hier lese ich, was der Standard dazu sagt; Ich bin sicher, dass jemand darauf hinweisen, was mir fehlt:
C99 sagt über Umwandlungen von Funktionszeigern (6.3.2.3/8 „Pointers“):
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.
In einem Ausdruck, der Kennung 10 wertet einen Funktionszeiger aus.
Der Unterausdruck ((void(*)())exit)
konvertiert den Funktionszeiger, den auswertet, in einen Funktionszeiger vom Typ void (*)()
. Dann wird ein Funktionsaufruf wird durch diesen Zeiger gemacht, vorbei an der int
Argument 0.
Die Standardbibliothek enthält eine Funktion exit
benannt, die den folgenden Prototyp hat:
void exit(int status);
Die Norm sagt auch (7.1.4/2 „Verwendung von Bibliotheksfunktionen“):
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
Ihr Programm enthält nicht den Header, den Prototyp enthält, sondern den Funktionsaufruf durch die umgewandelten Zeiger gemacht verwendet die ‚Erklärung‘ in der Besetzung zur Verfügung gestellt. Die Deklaration in der Umwandlung ist keine Prototyp-Deklaration, daher müssen wir feststellen, ob der Funktionstyp , wie von der Standardbibliothek definiert, und der Funktionstyp des konvertierten Funktionszeigers in Ihrem Programm kompatibel sind. Die Norm sagt (6.7.5.3/15 „Funktionsdeklaratoren (einschließlich Prototypen)“)
For two function types to be compatible, both shall specify compatible return types. ... If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions
Es scheint mir, dass die konvertierte Funktionszeiger eine kompatible Funktionstyp hat - der Rückgabetyp ist das gleiche (void
) und Der Typ des einzelnen Parameters ist int
nach den Standardargumentenpromotions. So scheint es mir, dass es hier kein undefiniertes Verhalten gibt.
Update: Nach ein wenig mehr Gedanken darüber, könnte es sinnvoll sein 7.1.4/2 zu interpretieren, dass ein ‚selbsterklärte‘ Bibliothek Funktionsname korrekt (wenn auch nicht unbedingt deklariert werden muß mit einem Prototyp, aber mit einem korrekten Rückgabetyp). Zumal der Standard auch besagt, dass "alle Bezeichner mit externer Verknüpfung in einem der folgenden Unterklauseln ... immer für die Verwendung als Bezeichner mit externer Verknüpfung reserviert sind" (7.1.3).
Also ich denke, ein vernünftiges Argument kann gemacht werden, dass das Programm undefiniert Verhalten hat.
gcc 4.7.2 denkt dies: exit.c: 6: 22: Hinweis: Wenn dieser Code erreicht ist, wird das Programm abgebrochen. Also muss ich davon ausgehen, dass die gcc-Entwickler dies als undefiniertes Verhalten ansehen. Da Sie in der Vergangenheit eine negative Sicht auf gcc geäußert haben, können Sie die Meinung von gcc ignorieren. Es gibt weitere Fehler bei der Definition von exit(). –
Eigentlich sagt es in meinem Fall sogar: 'Fehler: zu viele Argumente zu funktionieren', was natürlich stimmt. –
@Haroogan: C und C++ sind verschiedene Sprachen. –