Betrachten Sie die folgende Struktur:
struct s {
int a, b;
};
Typischerweise hat 1 diese Struktur die Größe 8 und die Ausrichtung 4.
Was ist, wenn wir zwei struct s
Objekte erstellen (genauer gesagt, wir schreiben zwei solche Objekte in den zugewiesenen Speicher), wobei das zweite Objekt das erste überlappt?
char *storage = malloc(3 * sizeof(struct s));
struct s *o1 = (struct s *)storage; // offset 0
struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4
// now, o2 points half way into o1
*o1 = (struct s){1, 2};
*o2 = (struct s){3, 4};
printf("o2.a=%d\n", o2->a);
printf("o2.b=%d\n", o2->b);
printf("o1.a=%d\n", o1->a);
printf("o1.b=%d\n", o1->b);
Ist etwas an diesem Programm undefiniertes Verhalten? Wenn ja, wo wird es undefiniert? Wenn es nicht UB ist, wird garantiert immer Folgendes gedruckt:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
Insbesondere möchte ich wissen, was mit dem Objekt passiert, auf das hingewiesen wird, o1
wenn o2
, was es überlappt, geschrieben wird. Ist es weiterhin erlaubt, auf den nicht überlasteten Teil ( o1->a
) zuzugreifen ? Ist der Zugriff auf das überlastete Teil o1->b
einfach der gleiche wie der Zugriff o2->a
?
Wie gilt hier der effektive Typ ? Die Regeln sind klar genug, wenn Sie über nicht überlappende Objekte und Zeiger sprechen, die auf dieselbe Position wie der letzte Speicher verweisen. Wenn Sie jedoch über den effektiven Typ von Teilen von Objekten oder überlappenden Objekten sprechen, ist dies weniger klar.
Würde sich etwas ändern, wenn der zweite Schreibvorgang von einem anderen Typ wäre? Wenn die Mitglieder sagen würden int
und short
nicht zwei int
s?
Hier ist ein Godbolt, wenn Sie dort damit spielen möchten.
1 Diese Antwort gilt für Plattformen, auf denen dies ebenfalls nicht der Fall ist: Einige haben möglicherweise Größe 4 und Ausrichtung 2. Auf einer Plattform, auf der Größe und Ausrichtung gleich waren, würde diese Frage nicht zutreffen, da ausgerichtete, überlappende Objekte dies tun würden unmöglich sein, aber ich bin mir nicht sicher, ob es eine solche Plattform gibt.