Ein grundlegender Unterschied zwischen C und Java besteht darin, dass, wenn man bestimmte leicht identifizierbare Merkmale von Java vermeidet (z. B. jene im Unsafe
Namespace), jede mögliche Aktion, die man versuchen kann - einschließlich "fehlerhafter" -, einen begrenzten Bereich möglicher Ergebnisse hat . Während dies Unsafe
die Möglichkeiten in Java einschränkt - zumindest ohne den Namespace zu verwenden -, ist es auch möglich, den Schaden zu begrenzen, der durch ein fehlerhaftes Programm oder - was noch wichtiger ist - durch ein Programm verursacht werden kann, das korrekt verarbeitet wird gültige Dateien, wird jedoch nicht besonders gegen fehlerhafte Dateien geschützt.
Herkömmlicherweise verarbeiteten C-Compiler viele Aktionen in "normalen" Fällen auf standardmäßige Weise, während sie viele Eckfälle "auf eine für die Umgebung charakteristische Weise" verarbeiteten. Wenn man eine CPU verwendet, die bei einem numerischen Überlauf einen Kurzschluss aufweist und Feuer fängt und verhindern möchte, dass die CPU Feuer fängt, muss man Code schreiben, um einen numerischen Überlauf zu vermeiden. Wenn man jedoch eine CPU verwendet, die Werte auf Zweierkomplement-Weise perfekt glücklich abschneidet, muss man Überläufe nicht vermeiden, wenn ein solches Abschneiden zu einem akzeptablen Verhalten führen würde.
Modernes C geht noch einen Schritt weiter: Selbst wenn man auf eine Plattform abzielt, die natürlich ein Verhalten für einen numerischen Überlauf definiert, für den der Standard keine Anforderungen auferlegt, kann ein Überlauf in einem Teil eines Programms das Verhalten anderer Teile des Programms beeinflussen Programm in willkürlicher Weise, die nicht an die Gesetze der Zeit und der Kausalität gebunden ist. Betrachten Sie zum Beispiel Folgendes:
uint32_t test(uint16_t x)
{
if (x < 50000) foo(x);
return x*x; // Note x will promote to "int" if that type is >16 bits.
}
Ein "moderner" C-Compiler, dem so etwas wie das Obige gegeben ist, könnte zu dem Schluss kommen, dass er den Aufruf von "foo" bedingungslos ausführen kann, da die Berechnung von x * x überlaufen würde, wenn x größer als 46340 ist. Beachten Sie, dass selbst dann, wenn es akzeptabel wäre, ein Programm abnormal zu beenden, wenn x außerhalb des Bereichs liegt, oder wenn die Funktion in solchen Fällen einen beliebigen Wert zurückgibt, der Aufruf von foo () mit einem außerhalb des Bereichs liegenden x weit darüber hinausgehende Schäden verursachen kann eine dieser Möglichkeiten. Herkömmliches C würde keine Sicherheitsausrüstung bieten, die über die vom Programmierer und der zugrunde liegenden Plattform gelieferten hinausgeht, aber Sicherheitsausrüstung würde den Schaden durch unerwartete Situationen begrenzen. Modern C umgeht jede Sicherheitsausrüstung, die nicht 100% effektiv ist, um alles unter Kontrolle zu halten.