Uma diferença fundamental entre C e Java é que, se evitarmos certos recursos facilmente identificáveis do Java (por exemplo, aqueles no Unsafe
espaço de nomes), todas as ações possíveis que se possa tentar - incluindo as "errôneas" - terão um alcance limitado de resultados possíveis . Embora isso limite o que se pode fazer em Java - pelo menos sem usar o Unsafe
namespace, também é possível limitar o dano que pode ser causado por um programa incorreto ou, mais importante, por um programa que processaria corretamente arquivos válidos, mas não é particularmente protegido contra arquivos errados.
Tradicionalmente, os compiladores C processavam muitas ações da maneira definida pelo padrão em casos "normais", enquanto processavam muitos casos de canto "de uma maneira característica do ambiente". Se alguém estivesse usando uma CPU que poderia causar um curto-circuito e pegar fogo se ocorresse um excesso numérico e quisesse evitar que a CPU pegasse fogo, seria necessário escrever um código para evitar o excesso numérico. Se, no entanto, alguém estivesse usando uma CPU que truncaria perfeitamente os valores da maneira complemento dois, não seria necessário evitar estouros nos casos em que esse truncamento resultaria em comportamento aceitável.
O C moderno leva as coisas um passo adiante: mesmo que alguém tenha como alvo uma plataforma que naturalmente definiria um comportamento para algo como excesso numérico em que o Padrão não impõe requisitos, o excesso em uma parte do programa pode afetar o comportamento de outras partes do programa de maneira arbitrária, não vinculada às leis do tempo e da causalidade. Por exemplo, considere algo como:
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.
}
Um compilador C "moderno", dado algo como o acima, pode concluir que, como o cálculo de x * x excederia se x for maior que 46340, ele poderá executar a chamada para "foo" incondicionalmente. Observe que, mesmo que seja aceitável que um programa termine de forma anormal se x estiver fora da faixa ou se a função retornar qualquer valor, nesses casos, chamar foo () com uma faixa fora da faixa x pode causar danos muito além qualquer uma dessas possibilidades. O tradicional C não forneceria nenhum equipamento de segurança além do fornecido pelo programador e pela plataforma subjacente, mas permitiria que o equipamento de segurança limite os danos causados por situações inesperadas. O C moderno ignora qualquer equipamento de segurança que não seja 100% eficaz em manter tudo sob controle.