Язык Си (C) все еще популярен не из-за ностальгии, а потому что на нем написан фундамент, на котором работает остальное ПО: ядра операционных систем, прошивки микроконтроллеров, интерпретаторы Python и PHP, СУБД, сетевые серверы. Вторая причина — C-интерфейс стал общим способом, которым библиотеки на разных языках вызывают друг друга. Третья — предсказуемость: минимальная среда выполнения и компиляторы почти под любой процессор.
Содержание
- Мини-словарь
- Где Си работает сегодня
- Причина 1. C-интерфейс — общий язык между языками
- Причина 2. Предсказуемость и минимальный рантайм
- Причина 3. Огромная кодовая база и совместимость
- Главный риск: безопасность памяти
- Rust — замена или дополнение?
- Что нового в стандарте C23
- Что говорят рейтинги
- Стоит ли учить C в 2026 году
- Выводы
- Где применяется / связь с практикой
- FAQ
Важно разделять три разные вещи, которые называют «популярностью»: место в рейтингах (про него ниже, с датой), объем уже работающего кода на C и выбор C для новых проектов. Первые две остаются высокими, а третья сужается: для нового кода, где важна безопасность, все чаще выбирают языки с безопасной работой с памятью. Ниже — где именно C держится, почему его трудно заменить и какие у этого риски.
Мини-словарь
- Стандарт языка — документ ISO/IEC 9899, который описывает, что делает корректная программа на C. Последняя опубликованная редакция — C23 (ISO/IEC 9899:2024).
- ABI (двоичный интерфейс) — соглашения платформы о том, как функция получает аргументы и возвращает результат на уровне машинного кода. Стандарт C его не задает: ABI определяет платформа (например, System V для Linux на x86-64 или соглашения Windows x64).
- FFI (интерфейс внешних функций) — механизм, которым один язык вызывает код, скомпилированный из другого. Почти все FFI умеют вызывать функции с C-интерфейсом.
- Неопределенное поведение (UB) — ситуация, для которой стандарт не задает результат: запись за границу массива, использование освобожденной памяти. Программа может упасть, а может молча продолжить с испорченными данными.
Где Си работает сегодня
| Область | Примеры | Почему именно C |
|---|---|---|
| Ядра ОС | Linux, ядро Windows (в основном C), XNU в macOS и iOS | Прямой доступ к памяти и железу, нет обязательного рантайма |
| Встраиваемые системы | Прошивки микроконтроллеров, автомобильные блоки, датчики | Компиляторы есть почти под любой чип, код помещается в килобайты |
| Интерпретаторы и рантаймы | CPython, Lua, Zend Engine (PHP), Ruby (MRI) | Нужны скорость и прямое управление памятью объектов |
| СУБД и хранилища | PostgreSQL, SQLite, Redis | Контроль над размещением данных и вводом-выводом |
| Сетевая инфраструктура | nginx, curl, OpenSSL, Git | Высокая нагрузка и переносимость на разные ОС |
Граница: «написано на C» не значит «только на C». В ядре Linux с версии 6.1 (декабрь 2022) есть поддержка модулей на Rust, в Windows часть компонентов написана на C++, а MySQL в основном написан на C++. Картина смешанная, но ядро этих проектов исторически на C и переписывается медленно.
Причина 1. C-интерфейс — общий язык между языками
Если библиотека экспортирует функции в стиле C, ее можно вызвать из Python, Go, Rust, Java, C#, Node.js. Поэтому даже библиотеки на C++ или Rust часто публикуют наружу C-интерфейс. Пример: функция на C и ее вызов из Python через стандартный модуль ctypes.
/* mathlib.c */
#include <stddef.h>
#include <stdint.h>
/* Сумма элементов массива: простая функция с C-интерфейсом */
int64_t sum_array(const int32_t *data, size_t n) {
int64_t total = 0;
for (size_t i = 0; i < n; i++) {
total += data[i];
}
return total;
}
# call_c.py
import ctypes, sys
lib_name = "./libmathlib.dylib" if sys.platform == "darwin" else "./libmathlib.so"
lib = ctypes.CDLL(lib_name)
lib.sum_array.argtypes = [ctypes.POINTER(ctypes.c_int32), ctypes.c_size_t]
lib.sum_array.restype = ctypes.c_int64
values = [10, 20, 30, 2_000_000_000, 2_000_000_000]
arr = (ctypes.c_int32 * len(values))(*values)
print(lib.sum_array(arr, len(values)))
Сборка и запуск (проверено на macOS с Apple clang 21 и Python 3.9; на Linux имя библиотеки — libmathlib.so):
gcc -O2 -Wall -shared -fPIC -o libmathlib.dylib mathlib.c
python3 call_c.py
4000000060
Сумма больше 2^31, поэтому в C она накапливается в int64_t, и Python получает ее без переполнения. Обратите внимание: описания argtypes и restype — это ручное обещание Python-стороне, какие типы у функции. Если описать их неверно, ctypes не заметит ошибки, и результат будет мусорным. Так же устроены NumPy, драйверы баз данных и многие игровые движки: быстрое ядро на C или C++, удобная обертка на другом языке.
Причина 2. Предсказуемость и минимальный рантайм
Программе на C не нужна виртуальная машина или сборщик мусора. Стандарт описывает даже freestanding-реализацию — режим без операционной системы, где доступна лишь малая часть стандартной библиотеки. Именно так пишут прошивки для микроконтроллеров с десятками килобайт памяти.
Упрощение, которое часто повторяют: «C быстрый, потому что выполняется на уровне процессора». Точнее так: компилятор переводит C в машинный код, и программист видит, где выделяется память и сколько стоит операция. Но скорость не гарантирована языком. C++ и Rust компилируются в сопоставимый код, а плохой алгоритм на C будет медленнее хорошего на Python с NumPy.
Причина 3. Огромная кодовая база и совместимость
Код, написанный под C89 или C99, обычно собирается и современным компилятором. Граница: GCC 15 по умолчанию перешел на -std=gnu23, где bool, true, false — ключевые слова, а объявления функций в старом стиле K&R больше не поддерживаются, поэтому для старого кода иногда приходится явно указать -std=gnu17. Переписать ядро ОС или СУБД на другой язык — это годы работы и новые ошибки в уже отлаженной логике. Поэтому компании поддерживают и развивают существующий код на C, а значит, нужны люди, которые его читают, отлаживают и безопасно меняют.
Главный риск: безопасность памяти
C не проверяет границы массивов и время жизни указателей. Вот типичная ошибка.
/* overflow.c - так делать нельзя */
#include <stdio.h>
#include <string.h>
int main(void) {
char name[8];
const char *input = "Dennis Ritchie"; /* 14 символов + '\0' */
strcpy(name, input); /* пишет за границу name */
printf("%s\n", name);
return 0;
}
Это неопределенное поведение, и результат зависит от платформы и флагов. В моем прогоне на macOS (Apple clang 21) программа аварийно завершилась с кодом 133 из-за встроенной проверки strcpy, а с -D_FORTIFY_SOURCE=0 — с кодом 134 (защита стека). На Linux с GCC 14 (Debian, без дополнительных флагов) тот же код напечатал Dennis Ritchie и завершился с кодом 0, хотя 7 байт записаны за границу массива — это худший вариант, потому что ошибку никто не видит. GCC при этом предупреждает еще на этапе компиляции: 'strcpy' writing 15 bytes into a region of size 8 overflows the destination.
Найти ошибку помогает AddressSanitizer: gcc -O0 -g -fsanitize=address overflow.c. Начало его отчета:
==13678==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x00016bc46a48 ...
WRITE of size 15 at 0x00016bc46a48 thread T0
#0 0x00010487aa1c in strcpy+0x458 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3aa1c)
#1 0x0001041b8904 in main overflow.c:8
Исправление — копировать с учетом размера буфера и проверять, поместилась ли строка:
/* safe.c */
#include <stdio.h>
int main(void) {
char name[8];
const char *input = "Dennis Ritchie";
int need = snprintf(name, sizeof name, "%s", input);
if (need >= (int)sizeof name) {
printf("обрезано: нужно %d байт, есть %zu\n", need + 1, sizeof name);
}
printf("%s\n", name);
return 0;
}
обрезано: нужно 15 байт, есть 8
Dennis
Это исправляет один класс ошибки в одном месте, но не делает программу безопасной целиком. Именно из-за таких ошибок регуляторы США (агентства CISA и NSA, 2022-2024) рекомендуют производителям переходить на языки с безопасной работой с памятью и публиковать планы такого перехода. Microsoft и команда Chromium в свое время оценивали долю уязвимостей, связанных с памятью, примерно в 70% серьезных ошибок своих продуктов.
Rust — замена или дополнение?
Rust дает скорость, сопоставимую с C, и проверяет владение памятью на этапе компиляции. Но на практике он чаще дополняет C, чем вытесняет: новые драйверы и модули пишут на Rust, а существующее ядро остается на C и вызывается через тот же C-интерфейс. Для встраиваемых систем важно и то, что под многие микроконтроллеры сертифицированный компилятор C есть, а инструменты Rust — не всегда.
Что нового в стандарте C23
Язык продолжает развиваться. В C23 появились nullptr, ключевые слова bool/true/false без заголовка, constexpr для объектов, typeof, двоичные литералы и разделитель разрядов.
/* c23.c */
#include <stdio.h>
int main(void) {
constexpr int limit = 1'000; /* разделитель разрядов и constexpr - C23 */
unsigned mask = 0b1010; /* двоичный литерал - стандарт с C23 */
bool ok = true; /* bool и true - ключевые слова в C23 */
int *p = nullptr; /* nullptr - C23 */
typeof(limit) copy = limit; /* typeof - C23 */
printf("__STDC_VERSION__ = %ld\n", __STDC_VERSION__);
printf("limit=%d mask=%u ok=%d p_is_null=%d copy=%d\n",
limit, mask, ok, p == nullptr, copy);
return 0;
}
gcc -std=c23 -Wall -Wextra -pedantic c23.c на Apple clang 21 выдает:
__STDC_VERSION__ = 202311
limit=1000 mask=10 ok=1 p_is_null=1 copy=1000
С флагом -std=c17 тот же файл не собирается: компилятор сообщает use of undeclared identifier 'constexpr'. Поддержка C23 зависит от версии компилятора: GCC 14 с -std=c23 собирает этот пример с тем же выводом, но печатает __STDC_VERSION__ = 202000 (предварительное значение), итоговое 202311 дают GCC 15 и свежий clang. Поэтому в проекте стоит явно указывать стандарт флагом.
Что говорят рейтинги
В индексе TIOBE C много лет держится в первой пятерке: в сентябре 2026 года он на втором месте после Python, годом ранее был третьим, а в 2024-2025 годах бывал и третьим, и четвертым. Индекс считает упоминания языка в поисковых системах, а не объем кода или вакансии, поэтому его стоит читать как сигнал интереса, а не как долю рынка. Точное место меняется от месяца к месяцу.
Стоит ли учить C в 2026 году
| Ваша цель | C нужен? | Комментарий |
|---|---|---|
| Встраиваемые системы, драйверы, ядро | Да, в первую очередь | Основной язык области |
| Системное ПО, СУБД, высоконагруженные серверы | Да, вместе с C++ или Rust | Нужно читать существующий код |
| Понять, как работают память и указатели | Полезно | Хорошая база перед C++ |
| Веб, аналитика, мобильная разработка | Не обязательно | Достаточно понимать, что под капотом |
Про синтаксис и основы языка подробнее — в статье о языке C и его основах, а сводка плюсов и минусов — в материале об областях применения C.
Выводы
- Си популярен прежде всего как фундамент: ядра ОС, прошивки, интерпретаторы, СУБД и сетевые серверы.
- C-интерфейс — общий способ связать библиотеки на разных языках, поэтому C нужен даже там, где основной код на Python или Rust.
- Предсказуемость и минимальный рантайм держат C во встраиваемых системах; скорость при этом не гарантируется языком автоматически.
- Главный риск — ошибки памяти; регуляторы рекомендуют для нового кода языки с безопасной памятью, а Rust чаще дополняет C, чем заменяет.
- Язык развивается: стандарт C23 добавил
nullptr,constexpr,typeofи другие возможности.
Где применяется / связь с практикой
Освойте тему на практике
Знание C открывает дорогу к системному программированию, но большинство современных проектов в этой области написаны на C++: игровые движки, браузеры, трейдинговые системы, высоконагруженные сервисы. Путь от указателей и ручной памяти в C к RAII, контейнерам и умным указателям C++ системно разбирается на курсе «C++-разработчик. Базовый уровень». Чтобы оценить формат, можно начать с открытых уроков Otus.
FAQ
C и C++ — это один язык?
Нет. C++ вырос из C и во многом совместим с ним, но это отдельные языки со своими стандартами; часть корректного кода на C не компилируется как C++.
Заменит ли Rust язык C полностью?
В обозримом будущем — вряд ли: объем существующего кода слишком велик. Реалистичный сценарий — новый код на Rust рядом со старым кодом на C через C-интерфейс.
Какой стандарт C выбрать для нового учебного проекта?
Если компилятор поддерживает C23 — его; если нужна совместимость со старыми тулчейнами, например для микроконтроллеров, чаще берут C11 или C17.



