Code mit undefiniertem Verhalten in C#
-
13-09-2019 - |
Frage
In C ++ gibt es viele Möglichkeiten, wie Sie Code schreiben können, den Sie kompilieren, aber ergeben undefiniertes Verhalten (Wikipedia). Gibt es etwas Ähnliches in C#? Können wir Code in C# schreiben, das kompiliert, aber undefiniertes Verhalten hat?
Lösung
Wie andere erwähnt haben, kann so ziemlich alles im "unsicheren" Block "unsicher" implementierende Verhaltensweisen erzielen. Durch den Missbrauch unsicherer Blöcke können Sie die Code Bytes ändern, aus denen die Laufzeit selbst besteht, und daher sind alle Wetten ausgeschaltet.
Der Eckfall der Integer Division hat ein implementierungsdefiniertes Verhalten.
Wenn Sie eine Ausnahme auswerfen und sie nie fangen, wird das implementierungsdefinierte Verhalten geführt-den Prozess beenden, einen Debugger starten und so weiter.
Es gibt eine Reihe anderer Situationen in C#, in denen wir gezwungen sind, Code zu emittieren, das implementiert ist. Zum Beispiel diese Situation:
http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx
Die Situationen, in denen ein sicheres, gut erzogenes C# -Programm implementiert, sollte jedoch sehr selten sein.
Andere Tipps
Ja! Es gibt auch in einem sicheren Kontext! (Nun, es ist die Implementierung definiert, zumindest nicht definiert zu sein)
Hier ist einer von Marek Safar und Vsadov in der Roslyn ProblemeEs gibt ein Missverhältnis zwischen C# und der CLI in Bezug auf bool
.
C# glaubt, dass es nur eine Art von Art von gibt true
, und eine Art von false
.
CLI glaubt das false
ist ein Byte mit 0 und alle anderen Werte sind true
.
Diese Diskrepanz bedeutet, dass wir C# zwingen können, um dies zu tun etwas a (geringfügig) interessant Dinge Ding:
//non-standard bool
//We're setting a bool's value to a byte value of 5.
var a = new bool[1];
Buffer.SetByte(a, 0, 5);
//non-standard bool
//We're setting a bool's value to a byte value of 10.
var b = new bool[1];
Buffer.SetByte(b, 0, 10);
//Both are true.
Console.WriteLine(a[0]);
Console.WriteLine(b[0]);
//But they are not the same true.
Console.WriteLine(a[0] == b[0]);
Die obigen Ausgaben:
true
true
false
Interessanterweise ist der Debugger anderer Meinung (muss die Wahrheit anders bewerten?)
Wie auch immer, in der Schlussfolgerung, zu der das C# -Team gekommen zu sein scheint, ist (Hervorhebung hinzugefügt):
Dh die Sprache wird völlig unbeteilig über nicht standardmäßige Bools bleiben. Die bestimmte Implementierung (wie in MS C# auf CIL) wird die Existenz von nicht standardmäßigen Bools anerkennen und ihr Verhalten als angeben nicht definiert
Wenn man sich das Wiki ansieht, sind die Situationen, in denen undefiniertes Verhalten stattfindet, entweder nicht zulässig oder aus einer Ausnahme in C#.
In unsicherem Code ist das undefinierte Verhalten, das ich jedoch für möglich halte, da, da Sie Zeiger usw. verwenden können.
EDIT: Es sieht so aus, als hätte ich Recht: http://msdn.microsoft.com/en-us/library/aa664771%28vs.71%29.aspx
Hat ein Beispiel für undefiniertes Verhalten in C#
Nach dem ECMA-334-Dokument (S. 473):
Ein Programm, das keine Vorkommen des unsicheren Modifikators enthält, kann kein undefiniertes Verhalten aufweisen.
Das fördert "implementierende" zum schlimmsten Fall, siehe Eric Lipperts Antwort.
Viele und Unterprogramme haben Anforderungen, die als:
Wenn Sie gültige Daten angegeben haben, erstellen Sie eine gültige Ausgabe.
Lagern Sie sich nicht in Bezug auf ungültige Inputs, wenn Sie die Nuklearraketen starten oder die Gesetze von Zeit und Kausalität negieren.
Eines der wichtigsten Designziele von Java- und .NET -Sprachen ist, dass der Code, sofern Code nicht sicher ist, die als "unsicher" gekennzeichnet sind Finalize
Kann aus der Sicht des Zeit-/Kausalität etwas seltsam sein, diese können als Ausnahmen von normalen Regeln der Kausalität und nicht als totaler Widerruf bezeichnet werden. Diese Situation unterscheidet sich stark von der Situation in C, in der viele Arten von datenabhängigen Fehlern (z. B. Überlauf des Ganzzahl) dazu führen können, dass Compiler sich auf willkürliche Weise verhalten, einschließlich der Annahmen, die erforderlich wären, um Überlauf zu vermeiden. Die wirklich schrecklichen Arten von undefiniertem Verhalten, die in der hypermodernen C -Philosophie ermutigt werden, gibt es in C# oder anderen .NET -Sprachen außerhalb von "unsicheren" Blöcken nicht.
Nicht wirklich im genauen Wiki -Sinne, aber ich nehme an, das offensichtlichste Beispiel, das mir in den Sinn kommt, ist einfach, einen Thread -Code zu schreiben, aber dann ist es in jeder Sprache so.
Im Allgemeinen würde ich nein sagen.
Verwenden Sie die automatische Variable, bevor Sie initialisiert werden.
Alle Variablen müssen initialisiert werden. Wenn nicht eine Ausnahme auftritt.
Durch Null teilen
Ausnahme wird ausgelöst.
Indexierung eines Arrays außerhalb der Grenzen
Ausnahme wird ausgelöst
Wie Aequitarum Custos darauf hinwies, können Sie einen unsicheren Code verwenden. Andererseits ist dies nicht wirklich C#, Sie entscheiden sich ausdrücklich aus der C# -E -Umgebung.