Принципиальное различие между C и Java заключается в том, что если не использовать некоторые легко идентифицируемые возможности Java (например, те, которые находятся в Unsafe
пространстве имен), то каждое возможное действие, в том числе «ошибочные», будет иметь ограниченный диапазон возможных результатов. , Хотя это ограничивает то, что можно делать в Java - по крайней мере, без использования Unsafe
пространства имен, оно также позволяет ограничить ущерб, который может быть вызван ошибочной программой или, что более важно, программой, которая будет правильно обрабатывать допустимые файлы, но не особо защищены от ошибочных.
Традиционно компиляторы C обрабатывали бы многие действия стандартным образом в «нормальных» случаях, в то же время обрабатывая многие угловые случаи «способом, характерным для среды». Если бы кто-то использовал процессор, который бы замыкался и загорался, если происходило переполнение чисел, и хотел бы избежать возгорания процессора, нужно было бы написать код, чтобы избежать переполнения числа. Однако, если бы кто-то использовал процессор, который бы совершенно удачно урезал значения в виде дополнения до двух, не нужно было избегать переполнений в тех случаях, когда такое усечение приводило бы к приемлемому поведению.
Современный C делает вещи на шаг впереди: даже если кто-то нацелен на платформу, которая естественным образом определяет поведение для чего-то вроде числового переполнения, когда Стандарт не налагает никаких требований, переполнение в одной части программы может повлиять на поведение других частей Программа произвольным образом не связана законами времени и причинности. Например, рассмотрим что-то вроде:
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.
}
«Современный» C-компилятор, имеющий что-то похожее на вышесказанное, может заключить, что, поскольку вычисление x * x будет переполнено, если x больше 46340, он может выполнить вызов «foo» безоговорочно. Обратите внимание, что даже если было бы приемлемо прекратить ненормальное завершение программы, если x выходит за пределы диапазона, или если в таких случаях функция должна возвращать любое значение, вызов foo () с x вне диапазона может привести к повреждению, намного превышающему любая из этих возможностей. Традиционный C не обеспечил бы никакой защитной экипировкой сверх того, что поставил программист и соответствующая платформа, но позволил бы защитной экипировке ограничить ущерб от неожиданных ситуаций. Modern C обойдет любое защитное снаряжение, которое не на 100% эффективно держит все под контролем.