Почему именно Си?

Понятно, что с таким инструментом, как машинный код, написать сколько-нибудь сложную программу практически невозможно — программист собьется после десятого же вбитого символа. Поэтому дальнейшим развитием стало появление языка ассемблера. Он максимально приближен к машинному коду, однако вводит простые и понятные вставки, которые по сути являются инструкциями процессора. Для сложения чисел, лежащих в регистрах r1 и r2, с сохранением результата в регистр r0 вам необходимо написать следующую строку:

ADD r0, r1, r2

Такой подход намного проще, однако не лишен недостатков. Программисту необходимо руками перекладывать данные из одних ячеек памяти в другие, прежде чем просто сложить два числа. Это неудобно и отвлекает от реальной задачи. Есть суп можно и вилкой, но это нерационально. Еще язык ассемблера плох тем, что меняется от платформы к платформе. Инструкции и их количество для каждой платформы могут отличаться, т.е. каждый раз придется запоминать команды.

22 июля 1962 года NASA произвела запуск аппарата Маринер-1 (англ. Mariner 1), который должен был отправиться к Венере. Однако спустя 293 секунды ЦУП принял решение о подрыве ракеты, так как она значительно отклонилась от курса. В результате проверки выяснилось, что в ходе полёта ракета потеряла радиосвязь с наземной станцией и стал выполняться не протестированный ранее участок кода, в одной инструкции которого был пропущен дефис (четких данных нет, некоторые утверждают, что это была точка). Точного описания того, что случилось, автор не нашёл. В любом случае код нужно тестировать.

Логичным развитием языков программирования стал уход в более высокоуровневые абстракции, которые упрощают работу программиста, автоматизируя рутинные задачи и ускоряя работу. Существует огромное количество разнообразных языков — С/С++, Go, Java, C#, Python, Erlang и другие. Их все можно разбить на три группы: компилируемые, компилируемые под виртуальную машину и интерпретируемые.

К первой группе относятся C/C++ и Go. Суть компиляции сводится к трансляции исходного кода в машинный. При этом запустить получившуюся программу можно только на той платформе, под которую она была скомпилирована (это касается не только архитектуры вычислительного ядра, но и операционной системы). Плюс ко всему, компиляция — довольно дорогое в вычислительном плане удовольствие.

Ко второй группе относятся Java и C#. Они тоже компилируются, но не в машинный код, а в так называемый байт-код. Запустить такую программу просто так не получится: она нуждается в другой программе, называемой «виртуальной машиной», которая переводит байт-код в машинный. Может показаться, что это глупо, однако такой подход позволяет при наличии разных виртуальных машин выполнять одну и ту же программу на разных платформах без перекомпиляции. Очевидный минус — меньше производительность и больше требования к железу, так как необходимо обслуживать виртуальную машину.

К третьей группе относятся Python и Erlang. В отличие от предыдущей группы, программа не компилируется в байт-код, она интерпретируется на лету, строчка за строчкой. Плюс и минус такого подхода ровно такие же, как и в случае с байт-кодом: для исполнения достаточно интерпретатора на целевой платформе, но расплачиваемся мы скоростью работы и потребляемыми ресурсами. Использовать языки второй и третьей группы для встраиваемых систем возможно, но ограниченность ресурсов не позволяет создавать большие и производительные программы. Поэтому оправданно использование компилируемого языка.

Но почему не Go? Язык Си появился значительно раньше и изначально использовался для системного программирования.


Изменено: