Sie scheinen verwechselt zu werden, was "effektiver Typ" betrifft: Es gilt für den Malloc'd-Raum, nicht für jeden Zeiger. Wie immer in C ist ein Zeiger ein separates Objekt mit separaten Eigenschaften für jeden Raum, auf den der Zeiger möglicherweise zeigt.
f
ist eine (benannte) Variable, daher ist ihr effektiver Typ immer derselbe wie der deklarierte Typ, nämlich Foo *
. Ähnlich ist der effektive Typ buf
immer char *
. Der einzige Zeitpunkt, zu dem sich der effektive Typ zur Laufzeit ändern kann, ist der dynamisch zugewiesene Speicherplatz.
Ihre Aufzählungspunkte und die Code-Kommentare sind wenig sinnvoll, daher habe ich beschlossen, Ihren Code neu zu kommentieren. Der Text bezieht sich jeweils auf den Code über dem Text:
Foo *f = malloc(sizeof(Foo));
OK. Nicht initialisierte Bytes wurden zugewiesen und f
Punkte zu ihnen. Der dynamisch zugewiesene Speicherplatz hat noch keinen effektiven Typ.
f->n = 1;
Die effektive Art des ersten sizeof(int)
Bytes wird dynamisch zugewiesenen Speicherplatz zu int
eingestellt. (* - aber siehe Fußnote)
char *buf = malloc(sizeof(Foo));
memcpy(buf, f, sizeof(Foo));
Die memcpy
Funktion bewahrt effektive Art von Objekten kopiert, so dass die effektive Art des ersten sizeof(int)
Bytes des Raumes, auf den buf
ist int
.
((Foo *)buf)->n++;
Erstens der Guss nicht über ein Ausrichtungsproblem, weil malloc
Raum korrekt für jede Art ausgerichtet ist. Wenn Sie auf den Zugriff von n
gehen, ist dies in Ordnung, weil ((Foo *)buf)->n
ein Wert vom Typ int
ist und ein Objekt vom effektiven Typ int
bezeichnet. So können wir problemlos lesen und schreiben.
memcpy(f, buf, sizeof(Foo));
memcpy
ist immer in Ordnung, da es die effektive Art setzt (Ihr Kommentar vorgeschlagen, dass Memcpy in einigen Fällen nicht in Ordnung sein könnte). Diese Zeile legt den effektiven Typ des Speicherplatzes fest, auf den f
zeigt, bis int
(da der Quellbereich effektiven Typ hatte int
).
f->n++;
Fein, gleiches Grundprinzip wie ((Foo *)buf)->n++
oben.
free(buf);
buf = (void *)f;
Redundante Besetzung. Der Raum, auf den f
zeigt, hat den effektiven Typ int
immer noch, da keine dieser Zeilen in diesen Raum geschrieben hat.
free(f);
Kein Problem.
Fußnote: Manche Menschen nehmen eine andere Interpretation des Ausdrucks f->n
(oder ((Foo *)buf)->n
WRT strenge Aliasing Sie sagen, dass f->n
als (*f).n
definiert ist und daher der damit verbundene effektive Art ist die Art der *f
, nicht die Art von. f->n
Ich stimme dieser Ansicht nicht zu, daher werde ich nicht weiter darauf eingehen.Es gab Vorschläge für C2X, um diese Situation und andere Grauzonen des strengen Aliasing zu klären.Für Ihren speziellen Code ist der Code immer noch korrekt Interpretation obwohl.
'buf = (void *) f' ist immer gültig (unabhängig vom Typ von' f'), weil die strengen Aliasregeln eine Ausnahme haben, die es einem 'char *' erlaubt, einen anderen Typ zu aliasieren. – user3386109