Betrachten Sie die folgende Struktur:
struct s {
int a, b;
};
Typisch1hat diese Struktur die Größe 8 und die Ausrichtung 4.
Was ist, wenn wir zwei erstellen struct s
Objekte (genauer gesagt schreiben wir zwei solcher 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 irgendetwas 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 gezeigt wird o1
Wenn o2
, die es überlappt, geschrieben. Ist es immer noch erlaubt, auf den unverschlüsselten Teil zuzugreifen (o1->a
)? Greift auf den geclobbered Teil zu o1->b
einfach das gleiche wie zugreifen o2->a
?
Wie funktioniert effektiver Typ hier bewerben? Die Regeln sind klar genug, wenn Sie von nicht überlappenden Objekten und Zeigern sprechen, die auf denselben Ort wie das letzte Geschäft zeigen, aber wenn Sie anfangen, über den effektiven Typ von Teilen von Objekten oder überlappenden Objekten zu sprechen, sind sie 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
statt zwei int
s?
Hier ist ein Gottriegel wenn du dort damit spielen willst.
1 Diese Antwort gilt auch für Plattformen, auf denen dies nicht der Fall ist: Einige könnten beispielsweise Größe 4 und Ausrichtung 2 haben. Auf einer Plattform, auf der Größe und Ausrichtung gleich wären, würde diese Frage nicht zutreffen, da ausgerichtete, überlappende Objekte dies wären unmöglich, aber ich bin mir nicht sicher, ob es eine solche Plattform gibt.
Ich bin mir ziemlich sicher, dass es UB ist, aber ich lasse einen Sprachanwalt Kapitel und Verse liefern.
– Barmar
7. April 2020 um 0:27 Uhr
Ich denke, dass der C-Compiler auf den alten Cray-Vektorsystemen erzwungen hat, dass Ausrichtung und Größe gleich sind, mit einem ILP64-Modell und erzwungener 64-Bit-Ausrichtung (Adressen sind 64-Bit-Wörter – keine Byte-Adressierung). Das führte natürlich zu vielen anderen Problemen….
– John D. McCalpin
9. April 2020 um 21:46 Uhr