Почему с С должен познакомиться каждый

Настоящее программирование.
19 сентября 2017326451Илья Бубнов26612025

C — один из прародителей всех современных языков программирования. Многие функции и конструкции, без которых сегодня невозможно представить код, впервые появились именно в С.

 

В 70−80-е годы он использовался и для программирования миниатюрных компьютеров, и для прошивки огромных вычислительных комплексов. И везде был успешен. Сегодня он также не утратил актуальность. Приложения, написанные на C, используются в:

  • системном ПО;
  • десктопных и мобильных приложениях;
  • базах данных;
  • корпоративном ПО;
  • игровых движках и мультимедиа.

Вы не прогадаете, если начнете свою карьеру в IT со знакомства с основами С.

Краткая история

Язык был разработан в 1972 году, но потом еще несколько лет активно менялся и дорабатывался. Одной из причин его появления на свет была ОС Unix, которая изначально писалась на ассемблере. Этот союз обеспечил переносимость системы, скорость разработки и читаемость кода, а С укрепился в статусе универсального языка.

В 1978 году Брайан Керниган и Деннис Ритчи опубликовали книгу «Язык программирования C». Эта книга служила неофициальной спецификацией в течение многих лет вплоть до 1989 года, когда C был стандартизован ANSI. Последняя версия языка — C11 появилась в 2011 году.

Отличие от С++

В 80-х годах выяснилось, что возможностей С недостаточно для создания сложного ПО. Так появилось развитие языка — C++, обладающий признаками ООП (инкапсуляция, полиморфизм, наследование и пр.). Он создан путем добавления функций при сохранении полной совместимости с C. Так как у них общая база, то выучить один язык, зная другой — не самая сложная задача. Именно поэтому в вакансиях и резюме они объединены как С/C++.

Видимая простота
В 2017 году С кажется сложным языком для чтения и понимания, но если оперировать цифрами — всё не так уж плохо. В частности, в языке используется всего 32 ключевых слова. Для сравнения, в Java — 50, в JavaScript — 63, а в COBOL, который долгое время был основой финансовой системы — 357. Кстати, в C++ используется 82 ключевых слова.

Строчный тип
В большинстве современных языков (Java, JavaScript, C#) для строк выделен отдельный тип, а в С — это просто массив символов, заканчивающийся на 0 (обозначается «\ 0»). При этом вы можете обозначить длину строки или игнорировать этот параметр. Однако как раз отсутствие строчного типа и ограничения размерности приводит к ошибке — переполнению буфера.
Первый червь, который когда-либо попадал в интернет, Morris worm, был результатом такой ошибки в ключевой части системного программного обеспечения на веб-серверах.

Вот пример такой ошибки. Программа компилируется отлично, но появляется сбой из-за переполнения буфера.

# include <stdio.h>
main()
{
 char *buf = "hello world";
 buf[12] = 'a';
 printf("%s\n", buf);
}

Большинство современных языков делают такие махинации невозможными. Даже C ++, который компилирует вышеописанный код, предоставляет явный тип std: string.

Указатели
Указатели — это прямые ссылки на ячейки памяти. Их применение делает код более гибким, но является причиной многих ошибок ПО. Часто они становятся причиной уязвимости на веб, почтовых и ftp-серверах. Даже сегодня, спустя 45 лет после рождения C, появляются новости об ошибках, вызванных ссылкой на недопустимые места памяти.

Ошибка безопасности SSL HeartBleed, обнаруженная в 2014 году, была как раз результатом неправильного использования указателей. Это в лишний раз иллюстрирует важность их понимания и применения.

Даже случайные ошибки BSOD («синий экран смерти Windows») часто вызваны неправильной обработкой указателя. Языки, отличные от C, не позволяют манипулировать указателем и, следовательно, не создают подобных ошибок.

Ссылки и указатели
В С есть схожее с указателем понятие — ссылка. Это адрес некоторой ячейки памяти. Таким образом, в C вы можете оперировать памятью, её адресом (ссылкой) и представлением (переменной). А ведь есть еще lvalue.

Кстати, массивы в С можно вызывать и ссылкой, и указателем. С одной стороны, это удобно и позволяет манипулировать большими объемами памяти. С другой — еще одно поле для критических ошибок.

Имена для компиляции
Макросы в С — функции препроцессора, используемые для замены значения, имени, выражения, и даже включения/выключения кусков кода во время компиляции. Это еще один инструмент для повышения читаемости программы. Куда более распространенное название — дефайны, произошедшее от ключевого слова #define.

С их использованием портирование ПО на любую архитектуру и платформу проходит бесшовно, так как различия в именах не играют роли.

Ничего подобного нет ни на Java, ни на Python, ни на JavaScript.

Инкапсуляция в файлы
В C нет понятия класса и, следовательно, нет регулировки видимости. Единственная инкапсуляция, предоставляемая C — файл. Функции, глобальные переменные и типы, определенные в исходном файле, видны внутри этого файла, только если они не экспортированы. Ключевые слова static и extern предоставляются с целью контроля видимости имен переменных и функций.

Напротив, другие языки, такие как C ++, Java и Python, поддерживают классы и инкапсуляцию, которая идет с классами.

Внешние библиотеки
Помимо базовых языковых конструкций, более сложные функции в C делегируются внешним библиотекам. Работа со строками, математика, ввод-вывод, сетевое взаимодействие, графика — для каждого вида кода необходимо подключение дополнительного модуля. Другие языки обычно используют одну большую библиотеку, содержащую функции на все случаи жизни.
Это удобно для новичка, но не слишком полезно для понимания.

Заключение

Си был могущественным в 70- годах прошлого века, им остается и в 2017. Да, современные языки сделали код безопаснее, а программирование общедоступным. Разработчики больше не ломают голову над тем, как реализовать свои идеи, у них другой вопрос: «с помощью какого инструмента?». А это уже не романтика, а квест.

Изучайте С и будьте тру-разработчиками!