-
Was ist eine “Trap-Darstellung” in C (einige Beispiele könnten helfen)? Gilt das für C++?
-
Angesichts dieses Codes …
float f=3.5; int *pi = (int*)&f;
… und davon ausgegangen
sizeof(int) == sizeof(float)
tunf
und*pi
haben die gleiche binäre Darstellung/das gleiche Muster?
Fallendarstellung
Burt
zwöl
-
Eine Trap-Darstellung ist ein Sammelbegriff, der von C99 (IIRC, nicht von C89) verwendet wird, um Bitmuster zu beschreiben, die in den von einem Typ belegten Raum passen, aber ein undefiniertes Verhalten auslösen, wenn sie als Wert dieses Typs verwendet werden. Die Definition befindet sich in Abschnitt 6.2.6.1p5 (mit Tentakeln in ganz 6.2.6) und ich werde sie hier nicht zitieren, weil sie lang und verwirrend ist. Von einem Typ, für den solche Bitmuster existieren, wird gesagt, dass er Trap-Darstellungen “besitzt”. Kein Typ muss irgendwelche Trap-Darstellungen haben, aber der einzige Typ, den der Standard garantiert nicht Fallendarstellungen haben ist
unsigned char
(6.2.6.1p5, 6.2.6.2p1).Der Standard gibt zwei hypothetische Beispiele für Trap-Darstellungen an, von denen keines dem entspricht, was eine echte CPU seit vielen Jahren getan hat, also werde ich Sie nicht damit verwirren. EIN gut Beispiel einer Fallendarstellung (auch die nur etwas, das auf jeder CPU, auf die Sie wahrscheinlich stoßen, als Trap-Darstellung auf Hardwareebene qualifiziert ist) ist ein signalisierendes NaN in einem Fließkommatyp. C99 Annex F (Abschnitt 2.1) lässt das Verhalten der Signalisierung von NaNs explizit undefiniert, obwohl IEC 60559 deren Verhalten detailliert spezifiziert.
Es ist erwähnenswert, dass während Zeigertypen sind erlaubt, Trap-Darstellungen zu haben, sind Null-Zeiger nicht Falle Darstellungen. Nullzeiger verursachen nur undefiniertes Verhalten, wenn sie dereferenziert oder versetzt werden; andere Operationen auf ihnen (am wichtigsten Vergleiche und Kopien) sind genau definiert. Trap-Darstellungen verursachen undefiniertes Verhalten, wenn Sie lediglich lesen sie mit dem Typ, der die Trap-Darstellung hat. (Ob ungültig aber Nicht-Null-Zeiger werden oder sollten als Trap-Repräsentationen betrachtet werden und sind ein Gegenstand der Debatte. Die CPU behandelt sie nicht so, der Compiler jedoch möglicherweise.)
-
Der von Ihnen gezeigte Code hat ein undefiniertes Verhalten, aber das liegt an den Zeiger-Aliasing-Regeln, nicht an Trap-Darstellungen. So konvertieren Sie a
float
in dieint
mit der gleichen Darstellung (unter der Annahme, wie Sie sagen,sizeof(float) == sizeof(int)
)int extract_int(float f) { union { int i; float f; } u; u.f = f; return u.i; }
Dieser Code hat nicht spezifiziert (nicht undefiniertes) Verhalten in C99, was im Grunde bedeutet, dass der Standard nicht definiert welchen ganzzahligen Wert wird produziert, aber Sie bekommen etwas gültiger ganzzahliger Wert, es ist keine Trap-Darstellung, und der Compiler darf nicht optimieren, wenn Sie davon ausgehen, dass Sie dies nicht getan haben. (Abschnitt 6.2.6.1, Abs. 7. Meine Kopie von C99 enthält möglicherweise technische Berichtigungen – soweit ich mich erinnere war in der Originalveröffentlichung nicht definiert, wurde aber in einem TC in nicht spezifiziert geändert.)
-
tatsächlich ist es UB auf C99 (siehe Anhang J), was wahrscheinlich ein Versehen war (der Wortlaut an anderer Stelle scheint etwas anderes nahezulegen). In C1x ist es nicht mehr UB, und die Formulierung wurde klarer gemacht.
– ninjalj
17. Juli 2011 um 19:48 Uhr
-
Fehlerbericht/TC für dieses Problem in C99: www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htmff
– u0b34a0f6ae
27. Oktober 2011 um 21:36 Uhr
-
IA64 hat eine Trap-Darstellung für ganze Zahlen namens “Not a Thing” (NaT). Sehen open-std.org/jtc1/sc22/wg14/www/docs/n1208.htm und blogs.msdn.com/b/oldnewthing/archive/2004/01/19/60162.aspx Für mehr Information.
– Adam Rosenfield
16. November 2012 um 20:52 Uhr
-
Wenn Sie den von Ihnen zitierten Fehlerbericht sorgfältig lesen, werden Sie feststellen, dass NaT von ia64 ist nicht eigentlich eine C99-konforme Trap-Repräsentation (der DR bittet um eine Änderung, um es zu einer zu machen, aber AFAICT, das ist nie wirklich passiert). Eine C99-Trap-Darstellung für einen Typ muss ein Bitmuster sein, das in den sichtbaren Bereich passt, der diesem Typ zugewiesen ist; NaTs sind Out-of-Band. Dies ist eine der vielen Arten, in denen NaTs ein schlechtes Design sind; Der Old New Thing-Blog, den Sie zitieren, veranschaulicht einen anderen solchen Weg.
– zol
16. November 2012 um 21:08 Uhr
-
@supercat Ich glaube, du hast gerade das Verhalten einer Trap-Darstellung für beschrieben
int
.unsigned char
kann selbst keine Trap-Darstellungen haben, und Trap-Darstellungen für jeden anderen Typ dürfen ausdrücklich mit “lvalue-Ausdrücken mit Zeichentyp” gelesen werden. (C99 6.2.6.1p5)– zol
30. Juni 2013 um 19:23 Uhr
Undefiniertes Verhalten zum Aliasing eines Floats mit einem Pointer-to-int.
-
Ich stimme zu, dass es UB ist, verstößt gegen die strenge Aliasing-Regel. Ich habe das gefragt, weil ich glaube, dass es auf den meisten Compilern funktioniert. Siehe die Antwort von Chris Lutz hier: stackoverflow.com/questions/1121160/…
– Burt
17. Juli 2011 um 18:55 Uhr
-
@Burt: Markieren Sie dann die Compiler und geben Sie sie in der Frage an.
– Hündchen
17. Juli 2011 um 18:56 Uhr
-
@Burt: Das Aliasing eines Floats mit einem Int ist undefiniertes Verhalten aufgrund strenger Aliasing-Regeln, und es kann nicht davon ausgegangen werden, dass sie “auf den meisten Compilern funktionieren”. Aber,
char*
kann jeden Typ aliasieren, was ihn lediglich zu einem implementierungsdefinierten Verhalten machen würde. Alternativ können Sie verwenden__attribute__((may_alias))
wenn Sie GCC verwenden.– Joey Adams
17. Juli 2011 um 19:01 Uhr
MSN
Im Allgemeinen kann jeder Nicht-Trap-IEEE-754-Gleitkommawert auf einigen Plattformen problemlos als Ganzzahl dargestellt werden. Es gibt jedoch Gleitkommawerte, die zu unerwartetem Verhalten führen können, wenn Sie davon ausgehen alle Fließkommawerte haben eine eindeutige ganzzahlige Darstellung und Sie zwingen die FPU zufällig, diesen Wert zu laden.
(Beispiel entnommen aus http://www.dmh2000.com/cpp/dswap.shtml)
Wenn Sie beispielsweise mit FP-Daten arbeiten, die zwischen CPUs mit unterschiedlicher Endianness gemarshallt werden müssen, könnten Sie Folgendes in Betracht ziehen:
double swap(double)
Wenn der Compiler die Eingabe in ein FPU-Register lädt und es sich um eine Trap-Darstellung handelt, kann die FPU sie leider mit einer äquivalenten Trap-Darstellung zurückschreiben, die zufällig eine andere Bit-Darstellung ist.
Mit anderen Worten, es gibt einige FP-Werte, die keine entsprechende Bitdarstellung haben, wenn Sie nicht richtig konvertieren (mit richtig meine ich durch a union
, memcpy
über char *
oder andere Standardmechanismen).