C — компилируемый язык программирования общего назначения, созданный Деннисом Ритчи в Bell Labs в 1972 году для написания операционной системы Unix. Он пережил почти всё, что появилось в ту же эпоху, и причина проста: C лежит тонким слоем над машиной. Он даёт прямой доступ к памяти и к реальным возможностям процессора, но при этом читается как то, что написал человек.
Спустя полвека он остаётся языком, на котором строят другие языки.
Полная программа на C
Вот форма всего языка в шести строках. Нажмите Run.
#include <stdio.h> подтягивает объявления стандартного ввода-вывода, чтобы printf был известен. main — точка, с которой начинается любая программа на C. printf выводит текст, \n — перевод строки, а return 0 сообщает операционной системе, что программа завершилась успешно. Это законченная, компилируемая программа — её не нужно заворачивать в класс, и под ней нет никакого фреймворка.
Чем C отличается
Большинство современных языков прячут машину от вас. C намеренно этого не делает.
- Он компилируется в машинный код. Программа на C превращается в машинные инструкции для конкретного процессора и выполняется напрямую, без интерпретатора и виртуальной машины посередине.
- Памятью вы управляете сами. Сборщика мусора нет. Вы запрашиваете память и возвращаете её. Это больше работы, и это же причина того, что программы на C потребляют так мало памяти и имеют такое предсказуемое время работы.
- Он маленький. В C около 32 ключевых слов. Весь язык помещается в голове, чего не скажешь о C++, Java или Python.
- Среды выполнения почти нет. Программа на C может работать на микроконтроллере с несколькими килобайтами ОЗУ и вообще без операционной системы.
Плата — честность вместо безопасности. C позволит вам прочитать за концом массива или использовать уже освобождённую память и не остановит вас. У этих ошибок есть имена — ошибки сегментации, утечки памяти, неопределённое поведение, — и изучение C во многом означает умение их избегать.
Где C работает на самом деле
C — не исторический курьёз. Он прямо сейчас работает на устройстве, с которого вы это читаете, причём в нескольких местах сразу.
- Операционные системы. Ядро Linux — это примерно 30 миллионов строк на C. Большие части Windows и ядра Apple тоже написаны на C.
- Встраиваемые системы. Микроконтроллеры в автомобилях, термостатах, медицинских приборах, роутерах и стиральных машинах программируются подавляющим большинством на C. Когда на всём чипе 32 КБ памяти, C зачастую единственный реалистичный вариант.
- Базы данных. SQLite, PostgreSQL, MySQL и Redis — программы на C.
- Среды выполнения языков. CPython, эталонный интерпретатор Python, написан на C. Как и MRI для Ruby, движок Zend для PHP и ядро Lua. Когда Python «слишком медленный», решением обычно оказывается расширение на C.
- Инструменты и библиотеки. Git, curl, FFmpeg, OpenSSL, zlib, снова SQLite — инфраструктурный слой вычислений написан на C.
Именно поэтому важен двоичный интерфейс приложений C: почти каждый язык умеет вызывать функцию на C. У Python, Rust, Go, Java и JavaScript есть способ дотянуться до библиотек на C. C — это лингва франка между языками.
Зачем учить C
Есть два честных ответа, и они адресованы разным людям.
Если вы хотите работать с системами — ядрами, драйверами, встраиваемой прошивкой, базами данных, — C является рабочим языком этой области, и большинство вакансий в ней называют его прямо (часто рядом с C++ или Rust). В Linux, PostgreSQL или кодовую базу для микроконтроллера трудно что-то внести, не читая C свободно.
Если вы хотите лучше владеть тем языком, которым уже пользуетесь, C покажет, что лежит под ним. После C вы знаете, почему индекс массива начинается с нуля, чем на самом деле является строка, почему передача большого объекта по значению дорога, что такое стек и куча и на что на самом деле указывает нулевой указатель. Эти понятия есть в каждом языке; в C они видны, а не спрятаны.
Эта программа — три строки на C и одновременно полная демонстрация того, что такое переменная: именованная коробка по некоторому адресу. В большинстве языков такой вопрос даже нельзя задать.
C и C++
C++ появился в 1979 году как «C с классами» и вырос в один из самых объёмных существующих языков: классы, шаблоны, исключения, перегрузка операторов, STL, умные указатели и стандартная библиотека, рядом с которой вся спецификация C выглядит крошечной.
Как это соотносится на практике:
- C++ сохранил синтаксис C, поэтому
if,for,while, операторы, указатели и массивы выглядят одинаково в обоих языках. - Большая часть хорошо написанного кода на C компилируется как C++, за некоторыми исключениями (например, в C++ результат
mallocнужно приводить к типу). - Код на C++ почти никогда не является корректным C.
Если вы собираетесь изучать оба, начать с C — реальное преимущество: C++ прямо надстраивается над моделью памяти C, а те части C++, что сбивают с толку сильнее всего — указатели, ссылки, семантика копирования, деструкторы, — это всё ответы на проблемы, которые C показывает открыто.
При этом C не является подмножеством C++ ни в каком официальном смысле. Это отдельные стандарты, развивающиеся независимо, и в современном C есть возможности, которых нет в C++ (именованные инициализаторы появились в C99, указатели restrict, массивы переменной длины).
Какой именно C: версии стандарта
C стандартизован, и версия имеет значение, когда вы читаете старый код.
| Стандарт | Год | Чем важен |
|---|---|---|
| C89 / C90 | 1989 | Древняя база. Переменные объявляются только в начале блока. |
| C99 | 1999 | Комментарии //, объявление переменных где угодно, bool через stdbool.h, long long |
| C11 | 2011 | Потоки, атомарные операции, более безопасные библиотечные функции |
| C17 | 2018 | Выпуск C11 с исправлениями — сегодняшнее значение по умолчанию |
| C23 | 2024 | true/false/bool как ключевые слова, nullptr, двоичные литералы |
Эта документация ориентируется на C17 и отдельно отмечает возможности C99+, где это важно. Компиляторы по умолчанию берут что-то современное, но можно указать явно:
gcc -std=c17 -Wall -Wextra hello.c -o hello
Чего в C нет
Часть понимания C — это знание того, чего в нём не хватает, потому что почти на любой вопрос «а как мне...» здесь другой ответ, чем в современном языке.
- Нет строк. Строка в C — это массив
char, заканчивающийся нулевым байтом. Склеить две из них означает вызвать функцию и позаботиться о том, хватит ли места в приёмнике. - Нет коллекций. Ни списков, ни словарей, ни множеств. Есть массивы фиксированного размера и указатели; хеш-таблицу вы пишете сами или подключаете библиотеку.
- Нет исключений. Функции сообщают об ошибке, возвращая особое значение —
-1,NULLили код состояния, — а вызывающий обязан его проверить. - Нет обобщений и перегрузки. Одно имя функции означает одну функцию. Поэтому в стандартной библиотеке есть
abs,labsиfabsдля трёх разных типов. - Нет пространств имён и модулей. Все не-
staticфункции делят одно глобальное пространство имён, поэтому библиотеки на C снабжают всё префиксами (sqlite3_open,png_read_info). - Нет сборщика мусора. Каждому
mallocнужен парныйfree, а забывчивость — это утечка памяти.
Ничто из этого не упущение. Часть — это машинерия времени выполнения, которую C отказывается нести (сборщик мусора, раскрутка исключений, растущие строки), и в этом во многом причина того, что он помещается на чип с 2 КБ ОЗУ; другие же, вроде пространств имён и обобщений, — это возможности языка, попросту появившиеся позже, чем был задуман C, и не взятые внутрь, чтобы язык остался маленьким.
Буфер занимает 32 байта, потому что вы решили, что этого достаточно. C ничего не проверит, и это решение — весь характер языка в одной строке.
Трудный ли C?
C маленький, но не прощает ошибок. Синтаксиса для запоминания немного — весь язык можно прочитать за неделю. Времени требует дисциплина: следить, кто владеет каким куском памяти, помнить, что строка — это просто байты, заканчивающиеся нулём, проверять, что указатель не нулевой, прежде чем идти по нему.
Трудность C — по большей части не в его понятиях, а в отсутствии страховки: компилятор не спасёт вас ни от записи за границу массива, ни от висячего указателя, поэтому вы учитесь быть точными. (Сами указатели в первый раз требуют настоящих усилий — это нормально, и глава об указателях разбирает их неспешно.) Эта точность — навык, который переносится на любой язык, которым вы пользуетесь потом.
Часто задаваемые вопросы
Что такое язык программирования C?
C — компилируемый язык программирования общего назначения, созданный Деннисом Ритчи в Bell Labs в 1972 году. Он даёт прямой контроль над памятью и близко отражает то, что реально делает процессор, — поэтому операционные системы, драйверы устройств и базы данных до сих пор пишут на нём.
Для чего C используется сегодня?
Ядра операционных систем (Linux, части Windows и macOS), встраиваемая прошивка в автомобилях, бытовой технике и микроконтроллерах, базы данных вроде SQLite и PostgreSQL, среды выполнения языков — CPython и Redis — и критичные к производительности библиотеки, которые вызывают другие языки.
Стоит ли учить C в 2026 году?
Да, по двум причинам. Это по-прежнему язык системной и встраиваемой разработки — большой и хорошо оплачиваемой области. И он учит тому, как на самом деле работают память, указатели и стек, — знание, которое делает вас сильнее в любом другом языке, потому что большинство из них реализованы на C.
В чём разница между C и C++?
C++ начинался как «C с классами» и сохранил почти весь синтаксис C, добавив объектно-ориентированное программирование, шаблоны, стандартную библиотеку и многое другое. C заметно меньше: ни классов, ни исключений, ни обобщений. Большая часть корректного кода на C компилируется как C++, но не наоборот.