Una differenza fondamentale tra C e Java è che se si evitano alcune caratteristiche facilmente identificabili di Java (ad esempio quelle nello Unsafe
spazio dei nomi), ogni possibile azione che si possa tentare - comprese quelle "errate" - avrà una gamma limitata di possibili esiti . Mentre questo limita ciò che si può fare in Java - almeno senza usare lo Unsafe
spazio dei nomi, rende anche possibile limitare il danno che può essere causato da un programma errato, o - soprattutto - da un programma che dovrebbe elaborare correttamente file validi ma non particolarmente protetti da file errati.
Tradizionalmente, i compilatori C elaborano molte azioni in modo definito dallo standard in casi "normali", mentre elaborano molti casi angolari "in un modo caratteristico dell'ambiente". Se si stesse usando una CPU che si sarebbe messa in corto circuito e avrebbe preso fuoco se si fosse verificato un overflow numerico e si fosse voluto evitare che la CPU prendesse fuoco, sarebbe necessario scrivere un codice per evitare un overflow numerico. Se, tuttavia, si stesse utilizzando una CPU che avrebbe troncato perfettamente i valori secondo il complemento a due, non si sarebbe dovuto evitare traboccamenti nei casi in cui tale troncamento avrebbe comportato comportamenti accettabili.
La moderna C fa un passo avanti: anche se si sta prendendo di mira una piattaforma che definirebbe naturalmente un comportamento per qualcosa come un overflow numerico in cui lo Standard non impone requisiti, l'overflow in una parte di un programma può influire sul comportamento di altre parti del programma in modo arbitrario non vincolato dalle leggi del tempo e della causalità. Ad esempio, considera qualcosa come:
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.
}
Un compilatore C "moderno", dato qualcosa di simile a quanto sopra, potrebbe concludere che, poiché il calcolo di x * x trabocca se x è maggiore di 46340, può eseguire la chiamata a "pippo" incondizionatamente. Si noti che anche se sarebbe accettabile terminare in modo anomalo un programma se x è fuori portata o se la funzione restituisce qualsiasi valore in questi casi, chiamare foo () con una fuori portata x potrebbe causare danni ben oltre una di queste possibilità. Il C tradizionale non fornirebbe alcun equipaggiamento di sicurezza oltre a quello fornito dal programmatore e dalla piattaforma sottostante, ma consentirebbe agli equipaggiamenti di sicurezza di limitare il danno da situazioni impreviste. La moderna C aggirerà qualsiasi attrezzatura di sicurezza che non sia efficace al 100% nel mantenere tutto sotto controllo.