Если вы выбираете между Си и Си плюс плюс как первым языком программирования и хотите писать приложения, игры или сервисы, берите C++: в нём есть почти всё из C, а сверх того классы, шаблоны, исключения и большая стандартная библиотека. Язык Си лучше выбрать, когда цель прямо связана с ним: прошивки микроконтроллеров, драйверы, ядра операционных систем или желание понять, как программа работает с памятью.
C++ вырос из C, хотя это давно два отдельных языка программирования со своими стандартами. Код на C в большинстве случаев собирается компилятором C++, и всё же не всегда: бывает файл, который в C работает, а в C++ даже не компилируется, пример в разделе о совместимости. Все примеры собраны Clang 21.1 на Windows.
- Что такое язык Си
- Что такое C++
- Главное отличие: процедурный и объектный подход
- Совместимость: один файл, два языка
- C и C++ в сравнении
- Преимущества и недостатки C и C++
- Что быстрее, C или C++
- Общая проблема: неопределённое поведение
- Где используется Си и где C++
- Что выбрать новичку
- Частые вопросы про C и C++
- Почему C до сих пор используется, если есть C++?
- Можно ли вызывать код на C из C++?
- Чем C# отличается от C и C++?
- Нужно ли знать C, чтобы работать с C++?
- Какой стандарт ставить при компиляции?
Что такое язык Си
Язык программирования C создал Деннис Ритчи в Bell Labs в 1972 году для работы над Unix. Уже через год большую часть ядра Unix переписали на нём, и с тех пор это главный язык системного программирования. Первый стандарт вышел в 1989 году (ANSI C), дальше были C99, C11, C17. Действующая версия называется C23, в ISO это документ 9899:2024.
Си называют языком низкого уровня среди языков высокого. В нём есть указатели, ручное управление памятью через malloc и free, структуры и функции, и почти ничего сверх этого. Классов, исключений и шаблонов нет. Простота языка позволяет по исходному коду легко понять, во что превратится программа и как данные лягут в память.
C статически типизированный язык: тип каждого выражения известен на этапе компиляции. Это верно и для C++.
Что такое C++
Бьёрн Страуструп начал делать «C с классами» в той же Bell Labs в 1979 году, а в 1983-м язык получил имя C++. Два плюса означают оператор инкремента: «C, увеличенный на единицу». Первый международный стандарт вышел в 1998 году, затем появились C++03, C++11, C++14, C++17 и C++20. Действует C++23 (ISO/IEC 14882:2024), а следующую версию, C++26, комитет по стандартизации закончил в марте 2026-го.
Возможности языка C++ шире, чем «C с классами»: объектно-ориентированное программирование (ООП) с наследованием и виртуальными функциями, шаблоны, обработка исключений, пространства имён, перегрузка функций и операторов. Стандартная библиотека предлагает контейнеры, строки и алгоритмы STL (стандартной библиотеки шаблонов), потоки, умные указатели. За эти возможности приходится платить сложностью: в стандарте C++23 2104 страницы против 758 у C23, а у многих конструкций есть несколько способов записи.
Главное отличие: процедурный и объектный подход
В языке C данные лежат в структуре, а функции существуют отдельно и получают структуру по адресу. Каждое выделение и освобождение видно в коде. Вот растущий стек целых чисел на C17:
#include <stdio.h>
#include <stdlib.h>
struct Stack {
int *items;
size_t len;
size_t cap;
};
int push(struct Stack *s, int value) {
if (s->len == s->cap) {
size_t n = s->cap ? s->cap * 2 : 4;
int *p = realloc(s->items, n * sizeof *p);
if (p == NULL) {
return -1; /* памяти нет: сообщаем кодом возврата */
}
s->items = p;
s->cap = n;
}
s->items[s->len++] = value;
return 0;
}
int main(void) {
struct Stack s = {NULL, 0, 0};
for (int i = 1; i <= 5; i++) {
if (push(&s, i * 10) != 0) {
free(s.items);
return 1;
}
}
printf("len = %zu, cap = %zu, top = %d\n", s.len, s.cap, s.items[s.len - 1]);
free(s.items); /* забудете эту строку, получите утечку */
return 0;
}
Команда clang -std=c17 -Wall stack.c -o stack, вывод программы:
len = 5, cap = 8, top = 50
Вместимость удвоилась с 4 до 8 на пятом элементе. Проверить результат realloc и освободить блок программист должен сам, и любая пропущенная строка превращается в утечку или падение. Поля структуры открыты, и другой код может записать туда что угодно.
Та же задача на C++20 с классом:
#include <iostream>
#include <vector>
class Stack {
public:
void push(int value) { values.push_back(value); } // нет памяти: std::bad_alloc
int top() const { return values.back(); }
auto count() const { return values.size(); }
private:
std::vector<int> values; // снаружи класса поле не видно
};
int main() {
Stack s;
for (int i = 1; i <= 5; i++) {
s.push(i * 10);
}
std::cout << "count = " << s.count() << ", top = " << s.top() << '\n';
} // здесь деструктор vector сам вернёт память
Команда clang++ -std=c++20 -Wall stack.cpp -o stack, вывод:
count = 5, top = 50

Поле values закрыто, изменить его можно только через методы класса: это инкапсуляция, и Stack становится собственным типом со своими правилами. Деструктор освобождает ресурсы, когда объект выходит из области видимости. Такой приём называется RAII (получение ресурса есть инициализация), и так же в C++ устроено управление ресурсами вообще: файлами, мьютексами, сетевыми соединениями. Нехватка памяти приходит исключением, которое удобнее поймать в одном месте через try/catch, вместо проверки кода возврата после каждого вызова.
Совместимость: один файл, два языка
Возьмём небольшую программу на языке C:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *buf = malloc(3 * sizeof(int));
if (buf == NULL) {
return 1;
}
printf("sizeof('a') = %zu\n", sizeof('a'));
free(buf);
return 0;
}
Как код на C она собирается и печатает:
sizeof('a') = 4
Тот же файл под именем demo.cpp компилятор C++ не пропускает:
demo.cpp:5:10: error: cannot initialize a variable of type 'int *' with an rvalue of type 'void *'
В C void * сам превращается в адрес любого типа данных, в C++ нужно явное приведение. Добавляем (int *) перед malloc, пересобираем как C++ и получаем другой результат:
sizeof('a') = 1
Символьный литерал 'a' в C имеет тип int, а в C++ тип char. Другие места, где код на C ломается в C++:
- переменная с именем
new,class,deleteилиtemplateв C законна, в C++ это ключевые слова; - массивы переменной длины (
int a[n], гдеnприходит из ввода) есть в C99, в стандартном C++ их нет; - слова
restrictв C++ нет.
С пустыми скобками всё наоборот: тут C подтянулся к C++. До C23 объявление void hello(); значило «аргументы неизвестны», и вызов hello(42) в режиме C17 проходил с предупреждением. В режиме C23 компилятор выдаёт ошибку too many arguments to function call, expected 0, have 1, как и в C++. Новая версия языка C получила из C++ и другие возможности: nullptr, bool, true и false как ключевые слова, constexpr и вывод типа через auto.
C и C++ в сравнении
| C (C23) | C++ (C++23) | |
|---|---|---|
| Подход | процедурное программирование | процедурное, объектно-ориентированное и обобщённое программирование |
| Классы и объекты, наследование | нет, только структуры | есть, с виртуальными функциями |
| Управление памятью | malloc и free вручную | деструкторы, контейнеры, умные указатели |
| Ошибки | коды возврата, errno | исключения и коды возврата |
| Шаблоны | нет, обходятся макросами и void * | есть |
| Перегрузка функций | нет | есть |
| Стандартная библиотека | ввод-вывод, строки char *, математика | то же, а ещё контейнеры, алгоритмы, string, std::thread |
| Объём стандарта ISO | 758 страниц | 2104 страницы |
Преимущества и недостатки C и C++
Язык C маленький и предсказуемый. Программист держит под контролем каждый байт, и в коде нет скрытых вызовов: нет деструкторов, которые срабатывают незаметно, и перегруженных операторов. Недостатки вытекают из того же: структуры данных вроде списков и словарей, динамические строки приходится писать самому или брать из сторонней библиотеки, а за границами массивов и утечками следит только человек. Например, текст длиннее буфера молча затрёт соседние байты.
Возможности C++ позволяют писать на более высоком уровне и не терять скорость: структуры данных и алгоритмы STL готовы, шаблоны (обобщённое программирование) позволяют создавать один код для разных типов данных, RAII снимает большую часть ручной работы с ресурсами. Но C++ сложнее и дольше учить, сообщение об ошибке в шаблоне может занять несколько экранов, а время компиляции большого проекта на C++ обычно больше, чем у сопоставимого кода на C, из-за тяжёлых заголовков и шаблонов.
Что быстрее, C или C++
Скорость зависит от кода, а не от названия языка. Все основные компиляторы собирают оба языка одним и тем же оптимизатором, поэтому одинаковый цикл по массиву превратится в одинаковые машинные команды. C++ строится на принципе нулевых издержек: то, чем программа не пользуется, ничего не стоит.
Производительность различается в конкретных приёмах. Виртуальная функция обычно вызывается через таблицу адресов, и такой вызов не всегда удаётся встроить. Исключения и информация о типах (RTTI) увеличивают размер исполняемого файла, поэтому в прошивках их часто отключают флагами -fno-exceptions и -fno-rtti. Бывает и наоборот: qsort из C вызывает функцию сравнения через указатель на каждой паре элементов, а sort из STL получает сравнение шаблонным параметром, и его можно встроить прямо в тело сортировки.
Если нужно сравнить скорость на своей задаче, обе версии пишут одинаково, собирают одним компилятором с одними флагами (например, -O2) и замеряют на реальных данных.
Общая проблема: неопределённое поведение
Оба языка программирования доверяют программисту. Выход за границу массива, чтение освобождённой памяти, переполнение знакового int считаются неопределённым поведением: стандарт не говорит, что произойдёт, и программа может долго работать, пока на другом компьютере не упадёт. Поэтому в крупных проектах на C и C++, например в Windows и Chrome, большая часть уязвимостей связана с памятью.
В C++ есть возможности снизить риск: vector::at проверяет индекс и бросает исключение, умные указатели сами удаляют объект, string следит за длиной. Однако обычный доступ по индексу v[i] не проверяется, даже если использовать контейнер, и старые приёмы из C в C++ по-прежнему работают. Из отладочных инструментов для обоих языков удобнее всего флаг -fsanitize=address в GCC и Clang: он ловит выход за границы и обращение к освобождённому блоку в момент ошибки и печатает строку, где она случилась.
Где используется Си и где C++
На языке C написаны ядро Linux (с версии 6.1 в него принимают и код на Rust), Git, SQLite, интерпретатор CPython. Он же используется для драйверов и прошивок: для некоторых микроконтроллеров компилятор C++ урезан или его нет совсем.
Язык C++ используется в больших проектах, где нужна скорость: браузер Chromium, инфраструктура компиляторов LLVM, движок Unreal Engine, графические редакторы, торговые системы. В разработке игр это основной язык популярных движков. Скетчи Arduino, кстати, тоже компилируются как C++.

Что выбрать новичку
Мы бы не советовали учить C только как ступеньку перед C++. Навыки C переносятся, но вместе с ними переносятся привычки, от которых в современном C++ отучивают: ручной malloc, массивы char вместо string, голые указатели для владения объектом. Если цель C++, начинайте сразу с него, с vector, string и умных указателей, и не пишите «C с классами».
C в роли первого языка подходит тому, кто идёт в разработку встраиваемых систем или хочет понять, что происходит с переменными на уровне адресов. С этой точки зрения C даже лучше: язык маленький, и на нём быстро видно, как структуры данных лежат в памяти.
Если ни игры, ни прошивки вас не тянут, а нужно просто освоить основы программирования, проще начать с Python. К C или C++ вы потом сможете вернуться с готовой базой: основные понятия вроде переменной, условия и цикла уже будут знакомы, и изучение нового языка сведётся к его особенностям.
Частые вопросы про C и C++
Почему C до сих пор используется, если есть C++?
Компилятор C есть почти для любого процессора, включая самые маленькие. Двоичный интерфейс функций C одинаков у всех компиляторов платформы, поэтому библиотеку на C может вызвать другой язык: Python, Java, Go. По той же причине библиотеки, написанные на C++, часто выставляют наружу интерфейс в стиле C.
Можно ли вызывать код на C из C++?
Да, это обычная практика в больших проектах. Заголовок C-библиотеки подключают внутри extern "C" { ... }, и компоновщик находит её функции по простым именам. Многие заголовки уже содержат такую обёртку под условием #ifdef __cplusplus.
Чем C# отличается от C и C++?
C# сделала Microsoft в 2000 году как язык программирования для платформы .NET. Программа на C# работает в среде выполнения .NET, ненужные объекты удаляет сборщик мусора, а синтаксис ближе к Java. Синтаксис у этого языка программирования похож на C++, но модель памяти другая: сборщик мусора вместо ручного освобождения, и с указателями разработчики на C# почти не сталкиваются. На C# пишут приложения для Windows, серверы и игры на Unity.
Нужно ли знать C, чтобы работать с C++?
Нет. Несмотря на историю, C++ учат как самостоятельный язык: базовый синтаксис у них общий, и его вы выучите в любом случае. Вызовы вроде printf или memcpy понадобятся при работе со старым кодом и интерфейсами операционной системы, их можно разобрать по мере надобности.
Какой стандарт ставить при компиляции?
Для учебных программ на C++ подойдёт C++20 (флаг -std=c++20): его основную часть поддерживают свежие версии трёх основных компиляторов. Для языка C разумный выбор C17, а C23 включайте, если нужны nullptr, constexpr и другие новинки. Поддержка C23 в компиляторах пока неполная: у MSVC, например, нет #embed.








