Vorausgesetzt unsigned int
keine Trap-Darstellungen hat, eine oder beide der unten mit (A) und (B) gekennzeichneten Aussagen undefiniertes Verhalten hervorrufen, warum oder warum nicht, und (insbesondere wenn Sie denken, dass eine davon wohldefiniert ist, die andere jedoch nicht) , halten Sie das für einen Mangel im Standard? Ich interessiere mich hauptsächlich für die aktuelle Version des C-Standards (dh C2011), aber ob dies in älteren Versionen des Standards oder in C++ anders ist, würde mich auch darüber interessieren.
(_Alignas
wird in diesem Programm verwendet, um jede Frage von UB aufgrund einer unzureichenden Ausrichtung zu beseitigen. Die Regeln, die ich in meiner Interpretation bespreche, sagen jedoch nichts über die Ausrichtung aus.)
#include <stdlib.h>
#include <string.h>
int main(void)
{
unsigned int v1, v2;
unsigned char _Alignas(unsigned int) b1[sizeof(unsigned int)];
unsigned char *b2 = malloc(sizeof(unsigned int));
if (!b2) return 1;
memset(b1, 0x55, sizeof(unsigned int));
memset(b2, 0x55, sizeof(unsigned int));
v1 = *(unsigned int *)b1; /* (A) */
v2 = *(unsigned int *)b2; /* (B) */
return !(v1 == v2);
}
Meine Interpretation von C2011 ist, dass (A) undefiniertes Verhalten provoziert, aber (B) wohldefiniert ist (um einen nicht spezifizierten Wert darin zu speichern v2
), Weil:
-
memset
ist definiert (§7.24.6.1), um in sein erstes Argument als-ob durch einen lvalue mit Zeichentyp zu schreiben, was für beide erlaubt istb1
undb2
gemäß dem Sonderfall am Ende von §6.5p7. -
Das Objekt
b1
hat einen deklarierten Typ,unsigned char[n]
. Daher ist auch sein effektiver Typ für Zugriffeunsigned char[n]
pro 6,5p6. Aussage (A) lautetb1
über einen lvalue-Ausdruck, dessen Typ istunsigned int
was nicht die effektive Art von istb1
noch eine der anderen Ausnahmen in 6.5p7, daher ist das Verhalten undefiniert. -
Das Objekt, auf das von gezeigt wird
b2
hat keinen deklarierten Typ. Der darin gespeicherte Wert (bymemset
) wurde (als ob) durch einen lvalue mit Zeichentyp, sodass der zweite Fall von 6.5p6 nicht zutrifft. Der Wert war es nicht kopiert von überall, also trifft der dritte Fall von 6.5p6 auch nicht zu. Daher ist der effektive Typ des Objekts der Typ des lvalue, der für den Zugriff verwendet wird, alsounsigned int
und die Regeln von 6.5p7 sind erfüllt. -
Schließlich gemäß 6.2.6.1, vorausgesetzt
unsigned int
hat keine Fallendarstellungen, diememset
Betrieb hat die Darstellung einiger nicht näher erstelltunsigned int
Wert in jedemb1
undb2
. Wenn also weder (A) noch (B) undefiniertes Verhalten hervorrufen, dann sind die tatsächlichen Werte inv1
undv2
sind nicht spezifiziert, aber sie sind gleich.
Kommentar:
Die Asymmetrie der „typbasierten Aliasing“-Regeln (d. h. 6.5p7), die es einem lvalue mit Zeichentyp erlaubt, auf ein Objekt mit einem beliebigen effektiven Typ zuzugreifen, aber nicht umgekehrt, ist eine ständige Quelle der Verwirrung. Der zweite Fall von 6.5p6 scheint speziell hinzugefügt worden zu sein, um zu verhindern, dass es ein undefiniertes Verhalten beim Lesen eines initialisierten Werts ist memset
(oder übrigens calloc
), aber da es nur für Objekte ohne deklarierten Typ gilt, ist es selbst eine zusätzliche Quelle der Verwirrung.
A
ist eindeutig eine Aliasing-Verletzung; aber der Standard scheint nicht klar zu sagen, welche Wirkungmemset
hat einen effektiven Typ– MM
21. Juni 2015 um 22:42 Uhr
Ich habe eine weitere Frage gestellt, die speziell darauf abzielt, den effektiven Typ von Daten zu beschreiben, von denen geschrieben wird
memset
– MM
21. Juni 2015 um 23:14 Uhr