Ich habe den folgenden Code (Include-Wächter aus Gründen der Einfachheit weggelassen):
= foo.hpp
=
= main.cpp
=
= foo_generator.hpp
=
= foo_generator.cpp
=
Dieser Code, so wie er aussieht, ist völlig in Ordnung ohne jede Warnung. Wenn mein Verständnis stimmt, sollte es ausgeben:
%Vor%Aber stattdessen wird zufällig angezeigt:
%Vor%Oder stürzt einfach ab.
Wenn ich die Vorwärtsdeklaration von FOO in foo_generator.hpp
durch #include "foo.hpp"
ersetze, funktioniert es.
Hier ist meine Frage: Führt die Rückgabe einer nach vorne deklarierten Struktur zu undefiniertem Verhalten? Oder was kann möglicherweise schiefgehen?
Verwendeter Compiler: MSVC 9.0 und 10.0 (beide zeigen das Problem)
Ich denke, ich habe das gleiche Problem. Dies geschieht mit kleinen Rückgabewerttypen und die Reihenfolge der Header-Including . Um dies zu vermeiden, verwenden Sie keine Rückgabetyp-Vorwärtsdeklaration oder Header in der gleichen Reihenfolge .
Für eine mögliche Erklärung sieh dir das an:
func.h
%Vor%func.cpp
%Vor%foo.h
%Vor%Beachten Sie, dass das ganze Foo in ein einzelnes CPU-Register passt.
func.asm (MSVS 2005)
%Vor%Wenn func () angegeben wird Foo's Größe ist unbekannt. Es weiß nicht, wie Foo zurückgegeben werden könnte. Also erwartet func () den Zeiger, um den Wertspeicher als seinen Parameter zurückzugeben. Hier ist es _ $ ReturnUdt $. Der Wert von Foo () wird dort kopiert.
Wenn wir die Reihenfolge der Header in func.cpp ändern, erhalten wir:
func.asm
%Vor%Nun weiß der Compiler, dass Foo klein genug ist, so dass es über das Register zurückgegeben wird und keine zusätzlichen Parameter benötigt werden.
main.cpp
%Vor%Beachten Sie, dass hier die Größe von Foo bekannt ist, wenn func () deklariert ist.
main.asm
%Vor%Der Compiler geht davon aus, dass func () den Wert über das Register zurückgibt. Es gibt keinen Zeiger auf die temporäre Position, um den Rückgabewert zu speichern. Aber wenn func () den Zeiger erwartet, schreibt es in den Speicher, der den Stapel korrumpiert.
Lassen Sie uns die Reihenfolge der Header ändern, also geht func.h zuerst.
main.asm
%Vor%Der Compiler übergibt den Zeiger, den func () erwartet, so dass keine Stapelbeschädigungen auftreten.
Wenn die Größe von Foo größer als 2 Ganzzahlen wäre, würde der Compiler immer den Zeiger übergeben.
Es funktioniert gut für mich unter GCC. Ich weiß nicht, warum es nicht wäre, da foo.hpp
vor foo_generator.hpp
enthalten ist.
Tags und Links c++ visual-c++ undefined-behavior