Ich bin auf folgendes C-Puzzle gestoßen:
F: Warum ist das folgende Programm auf IA-64 fehlerfrei, funktioniert aber auf IA-32 einwandfrei?
int main()
{
int* p;
p = (int*)malloc(sizeof(int));
*p = 10;
return 0;
}
Ich weiß, dass die Größe int
eines 64-Bit-Computers möglicherweise nicht der Größe eines Zeigers entspricht ( int
32 Bit und der Zeiger 64 Bit). Ich bin mir jedoch nicht sicher, wie dies mit dem oben genannten Programm zusammenhängt. Irgendwelche Ideen?
c
pointers
segmentation-fault
user7
quelle
quelle
stdlib.h
nicht dabei zu sein?#include stdlib.h
(für malloc)#include <stdlib.h>
ist es perfekt zu finden, aber das kommt nicht in Frage.sizeof(int) == sizeof(int*)
, auf der beispielsweise Zeiger über ein anderes Register alsint
s in der verwendeten Aufrufkonvention zurückgegeben werden, legitimerweise fehlschlagen .malloc()
. GCC sagt:warning: incompatible implicit declaration of built-in function 'malloc'
auch.Antworten:
Die Besetzung
int*
maskiert die Tatsache, dass ohne den richtigen#include
Rückgabetypmalloc
angenommen wirdint
. IA-64 hat zufällig,sizeof(int) < sizeof(int*)
was dieses Problem offensichtlich macht.(Beachten Sie auch, dass es aufgrund des undefinierten Verhaltens auch auf einer Plattform, auf
sizeof(int)==sizeof(int*)
der true gilt, immer noch fehlschlagen kann , wenn die aufrufende Konvention andere Register für die Rückgabe von Zeigern als Ganzzahlen verwendet.)In den häufig gestellten Fragen zu comp.lang.c wird erläutert, warum das Casting der Rückgabe von
malloc
niemals erforderlich und möglicherweise schlecht ist .quelle
new
in C ++ zu verwenden und C immer mit einem C-Compiler und nicht mit einem C ++ - Compiler zu kompilieren.int
wenn er nicht bekannt istmalloc
)void*
. Der aufrufende Code glaubt jedoch, dass die Funktion zurückkehrtint
(da Sie sich dafür entschieden haben, nichts anderes zu sagen), und versucht daher, den Rückgabewert gemäß der aufrufenden Konvention für a zu lesenint
. Zeigtp
daher nicht unbedingt auf den zugewiesenen Speicher. Es hat einfach so für IA32 funktioniert, weil anint
und avoid*
die gleiche Größe haben und auf die gleiche Weise zurückgegeben wurden. Auf IA64 erhalten Sie den falschen Wert.Höchstwahrscheinlich, weil Sie die Header-Datei für nicht einschließen
malloc
und der Compiler Sie normalerweise davor warnt, bedeutet die Tatsache, dass Sie den Rückgabewert explizit umwandeln, dass Sie ihm mitteilen, dass Sie wissen, was Sie tun.Das bedeutet, dass der Compiler erwartet
int
, dass ein zurückgegeben wird, vonmalloc
dem er dann in einen Zeiger umgewandelt wird. Wenn sie unterschiedlich groß sind, wird dir das Kummer bereiten.Aus diesem Grund haben Sie die Rückgabe nie
malloc
in C umgewandelt. Dievoid*
Rückgabe wird implizit in einen Zeiger des richtigen Typs konvertiert (es sei denn, Sie haben den Header nicht eingefügt. In diesem Fall hätte er Sie wahrscheinlich vor dem möglicherweise unsicheren int gewarnt). in Zeigerumwandlung).quelle
void *
implizit in einen anderen Zeigertyp konvertiert werden kann.int *p = malloc(sizeof(int))
funktioniert, wenn der richtige Prototyp im Gültigkeitsbereich ist, und schlägt fehl, wenn dies nicht der Fall ist (da dann das Ergebnis angenommen wirdint
). Mit der Besetzung würden beide kompilieren und letztere würde zu Fehlern führen, wennsizeof(int) != sizeof(void *)
.stdlib.h
, weiß der Compiler nichtmalloc
und auch nicht seinen Rückgabetyp. Es wird also nurint
als Standard angenommen.Aus diesem Grund kompilieren Sie niemals ohne Warnungen vor fehlenden Prototypen.
Die Besetzung wird für die C ++ - Kompatibilität benötigt. Es gibt wenig Grund (lesen Sie: kein Grund hier), es wegzulassen.
C ++ - Kompatibilität ist nicht immer erforderlich und in einigen Fällen überhaupt nicht möglich, in den meisten Fällen jedoch sehr einfach.
quelle