Раздел 1 — Языки и инструменты

Чем пишут программы, как текст становится исполняемым файлом и что делать, когда сборка не прошла

Прогресс курса Раздел 1 из 28

Что вы освоите в этом разделе

2 академических часа теории и 1 час практики: практическая работа №1 «Среда: сборка, предупреждения, отладчик» — на портале. С этого раздела нужен компьютер с Windows 10/11 или Linux. Все программы страницы — полные: их можно скопировать, собрать и запустить.
01

Зачем веб-разработчику C

Сайт на PHP или Python кажется далёким от C. Но под ним почти всё написано на C и C++:

ПрограммаЧто делает для сайтаЯзык
Linux, ядро Windowsоперационная система сервераC
nginx, Apacheпринимают HTTP-запросыC
PostgreSQL, MySQL, SQLite, Redisхранят данныеC, C++
интерпретаторы PHP и Python (CPython)выполняют код сайтаC
Chrome, Firefox, движок JavaScript V8показывают страницу и выполняют её скриптыC++
OpenSSL, zlib, libpngшифруют HTTPS, сжимают ответы, читают картинкиC

C — язык, на котором видно, как программа работает с памятью: где лежит число, сколько байт занимает строка, кто и когда освобождает память. Поэтому он и выбран для курса алгоритмов: сортировка, список или хеш-таблица на C пишутся целиком, без готовых «чёрных ящиков». Когда устройство понятно, курс переходит к C++ (раздел 20): там те же структуры данных уже есть в стандартной библиотеке, и на нём пишутся оконные и игровые приложения (разделы 25–28).

C и C++ — разные языки. C++ вырос из C и почти весь C принимает, но программы на них пишутся по-разному. До раздела 20 весь код курса — на C: файлы .c, компилятор gcc.
02

Компилятор и интерпретатор

Процессор выполняет машинные команды — числа в памяти. Программа — текст. Перевести текст в команды можно двумя способами.

Компилятор переводит текст программы целиком, заранее, один раз — и записывает результат в исполняемый файл (.exe в Windows, файл без расширения в Linux). Запускается потом только этот файл; ни исходный текст, ни компилятор для запуска не нужны. Языки, программы на которых обычно компилируют: C, C++, Go, Rust.

Интерпретатор читает текст программы при каждом запуске и сразу выполняет его. Без интерпретатора программа не запустится. Так работают Python, PHP, JavaScript в браузере.

Компиляция (C)Интерпретация (Python, PHP)
Когда находится опечатка в имени переменнойпри сборке, до первого запускакогда выполнение дойдёт до этой строки — может быть, через месяц работы сайта
Что нужно на компьютере пользователятолько исполняемый файл (для своей ОС и процессора)интерпретатор нужной версии и исходный текст
Скоростьмашинный код — быстромедленнее в разы и в десятки раз на циклах
Цикл «правка — проверка»правка → сборка → запускправка → запуск

Граница размыта: Java и C# компилируются в промежуточный код, который выполняет виртуальная машина; JavaScript в браузере сначала интерпретируется, а часто выполняемые функции компилируются прямо во время работы. Но для C всё просто: исходный текст → компилятор → исполняемый файл.

03

Стандарты C и C++

Язык C описан международным стандартом ISO/IEC 9899. Стандарт говорит, что значит каждая конструкция языка и что обязана уметь стандартная библиотека. Компилятор, который выполняет стандарт, соберёт одну и ту же программу одинаково в Windows, Linux и на микроконтроллере.

СтандартГодЧто появилось (примеры)
C89 / C901989–1990первый стандарт: язык в том виде, в каком его описали Керниган и Ритчи
C991999комментарии //, тип long long, bool из <stdbool.h>, объявление переменной в любом месте блока и в заголовке for
C112011_Static_assert, анонимные структуры, поддержка Юникода в строках; стандарт курса
C172018исправления C11 без новых возможностей
C232024bool, true, false и nullptr — ключевые слова, typeof, двоичные литералы 0b1010

У C++ свой стандарт (ISO/IEC 14882) и свои версии: C++98, C++11, C++14, C++17 (стандарт курса с раздела 20), C++20, C++23. Стандарт выбирается ключом компилятора: -std=c11 для C, -std=c++17 для C++.

Почему C11, а не C23. Программа курса должна собираться везде, где её будут собирать: в колледже, дома, на сервере. C11 полностью поддерживают gcc, clang и Microsoft Visual C++; C23 в 2026 году поддержан не везде и не целиком. Всё, что нужно курсу, в C11 есть.
04

Среда: компилятор, редактор, отладчик

Для работы нужны три программы. Редактор — в нём пишут текст программы. Компилятор — собирает программу. Отладчик — выполняет программу по шагам и показывает значения переменных. Интегрированная среда разработки (IDE — Qt Creator, CLion, Visual Studio) объединяет их в одном окне, но внутри у неё те же компилятор и отладчик. В курсе используется компилятор gcc (GNU Compiler Collection) и отладчик gdb; редактор — любой, например VS Code или Notepad++.

Windows. gcc для Windows называется MinGW-w64. Удобнее всего ставить его через MSYS2:

  1. Скачать установщик с msys2.org и установить в C:\msys64 (путь без пробелов и кириллицы).
  2. Открыть из меню «Пуск» терминал MSYS2 UCRT64 и выполнить:
pacman -Syu
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gdb make
  1. Добавить в переменную среды Path папку C:\msys64\ucrt64\bin — тогда gcc запускается из любой консоли Windows, а не только из терминала MSYS2.

Linux (Debian, Ubuntu):

sudo apt install gcc gdb make

Проверка — в новом окне консоли:

gcc --version
gdb --version

Обе команды должны вывести номер версии (gcc 13 и новее). Сообщение "gcc" не является внутренней или внешней командой (или gcc: command not found в Linux) значит, что компилятор не установлен или папка не добавлена в Path; после правки Path консоль нужно открыть заново.

Антивирус и свежие exe. Защитник Windows и другие антивирусы иногда удаляют или блокируют только что собранный exe: он новый и ничем не подписан. Признак — exe исчезает сразу после сборки или запуск завершается ошибкой доступа. Решение — папка с учебными проектами в исключениях антивируса (на компьютере колледжа — через лаборанта).
05

Первая программа

Создайте папку для курса без пробелов и кириллицы в пути (например, C:\alg\01), в ней — файл hello.c:

/* Первая программа на C */
#include <stdio.h>

int main(void)
{
    printf("Hello, world!\n");
    return 0;
}

Сборка и запуск — в консоли, в папке с файлом:

gcc -std=c11 -Wall -Wextra -pedantic hello.c -o hello
hello
Hello, world!
Часть командыЧто значит
-std=c11собирать по стандарту C11
-Wall -Wextraвключить предупреждения о подозрительном коде (по умолчанию большая часть выключена)
-pedanticпредупреждать обо всём, что не входит в выбранный стандарт: расширениях gcc, которые другой компилятор не примет
hello.cисходный файл
-o helloимя результата: hello.exe в Windows (расширение gcc добавит сам), hello в Linux

В Linux и в терминале MSYS2 программа из текущей папки запускается как ./hello — без ./ оболочка ищет команду только в папках из PATH. В cmd и PowerShell Windows — hello или .\hello.

Код возврата последней программы можно посмотреть: echo $? в Linux и MSYS2, echo %errorlevel% в cmd, $LASTEXITCODE в PowerShell. Для hello это 0.

Правило курса: каждая программа собирается командой gcc -std=c11 -Wall -Wextra -pedantic без единого предупреждения. Программа с предупреждениями на проверку не принимается: почти каждое предупреждение — ошибка, которая ещё не проявилась (пункт 07).
06

Этапы сборки

Одна команда gcc на самом деле запускает по очереди четыре программы:

  hello.c ──► препроцессор ──► hello.i ──► компилятор ──► hello.s
  исходный      #include,           текст          C →                ассемблер
  текст         #define             без #          ассемблер

  hello.s ──► ассемблер ──► hello.o ──► компоновщик ──► hello.exe
                              объектный      + код библиотек     исполняемый
                              файл           (printf и др.)      файл
ЭтапЧто делаетОстановиться на нём
Препроцессорвыполняет строки, начинающиеся с #: вставляет вместо #include текст заголовочного файла, подставляет макросы, убирает комментарииgcc -E hello.c -o hello.i
Компиляторпроверяет, что текст — правильная программа на C, и переводит её на язык ассемблераgcc -S hello.c → hello.s
Ассемблерпереводит ассемблер в машинный код — объектный файлgcc -c hello.c → hello.o
Компоновщик (линкер, ld)соединяет объектные файлы программы с кодом библиотек (там лежит сама printf) и оформляет исполняемый файл для ОСgcc hello.o -o hello

Откройте hello.i в редакторе: в нём сотни строк — это содержимое stdio.h и заголовков, которые подключает он сам, а ваша функция main — в самом конце. В stdio.h только объявление printf — её имя, параметры и тип результата. Код функции уже скомпилирован и лежит в библиотеке; его подставляет компоновщик.

Зачем знать этапы: по сообщению об ошибке видно, на каком этапе она случилась, а значит — где искать.

Вид сообщенияЭтапГде искать причину
fatal error: stdoi.h: No such file or directoryпрепроцессоримя заголовочного файла в #include
файл.c:5:22: error: … — с номером строки и столбцакомпиляторуказанная строка или строка над ней
undefined reference to …, ld returned 1 exit statusкомпоновщикфункция объявлена или вызвана, но её кода нет: опечатка в имени, не подключена библиотека
07

Ошибки и предупреждения

Сообщение компилятора имеет вид файл:строка:столбец: вид: текст. error — программа написана не по правилам языка, исполняемый файл не создан. warning — по правилам, но подозрительно; исполняемый файл создан. Под сообщением gcc печатает саму строку и знак ^ под местом ошибки.

Пропущена точка с запятой.

#include <stdio.h>

int main(void)
{
    printf("Hello\n")
    return 0;
}
semicolon.c: In function 'main':
semicolon.c:5:22: error: expected ';' before 'return'
    5 |     printf("Hello\n")
      |                      ^
      |                      ;
    6 |     return 0;
      |     ~~~~~~

Компилятор заметил ошибку, только увидев следующее слово return, но указывает место точно: строка 5, после закрывающей скобки — и даже подсказывает, что вставить. Когда ошибка в конце строки, сообщение часто указывает на начало следующей: смотрите и на строку выше.

Опечатка в имени.

int count = 5;
printf("%d\n", cout);
undeclared.c:6:20: error: 'cout' undeclared (first use in this function); did you mean 'count'?

Забыт #include. Без <stdio.h> компилятор не знает, что такое printf. С версии 14 gcc считает это ошибкой (раньше было предупреждение):

noinclude.c:3:5: error: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
noinclude.c:1:1: note: include '<stdio.h>' or provide a declaration of 'printf'

Ошибка компоновщика. Опечатка в имени main — int mian(void). Компилятор доволен: функцию mian написать можно. Но компоновщик не находит, с чего начинать программу:

Linux:    undefined reference to `main'
Windows:  undefined reference to `WinMain'
          collect2: error: ld returned 1 exit status

Номера строки нет — компоновщик работает с объектными файлами, а не с текстом. WinMain в Windows — потому что, не найдя main, библиотека пробует точку входа оконного приложения.

Предупреждение, которое нельзя пропускать. %d в printf означает «вывести целое», а передано вещественное число:

#include <stdio.h>

int main(void)
{
    printf("%d\n", 3.5);
    return 0;
}
format.c:5:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=]

Exe создан, и он выводит не 3 и не 3.5, а случайное число — разное на разных компьютерах и запусках. Предупреждение в квадратных скобках называет ключ, который его включил: -Wformat= входит в -Wall. Без -Wall предупреждения не было бы, а ошибка осталась бы.

Как исправлять ошибки: по одной, сверху вниз, пересобирая после каждой. Одна пропущенная скобка порождает десяток сообщений ниже, и они исчезнут вместе с первой. Читать нужно само сообщение, а не только номер строки: в нём обычно сказано, что ожидалось.
08

Отладчик gdb

Программа собралась без предупреждений, но выводит не то. Отладчик позволяет остановить её на нужной строке, выполнять дальше по одной строке и смотреть значения переменных. Программа считает сумму 1 + 2 + … + n и ошибается:

/* Сумма 1 + 2 + ... + n — с ошибкой, для отладчика */
#include <stdio.h>

int main(void)
{
    int n = 4;
    int sum = 0;
    for (int i = 1; i < n; i++) {
        sum = sum + i;
    }
    printf("sum = %d\n", sum);
    return 0;
}
sum = 6

Ожидалось 10. Цикл for будет в разделе 6; сейчас достаточно знать, что строка 9 выполняется несколько раз. Для отладки программа собирается с ключом -g — в exe записываются номера строк и имена переменных — и запускается под gdb:

gcc -std=c11 -Wall -Wextra -pedantic -g debugsum.c -o debugsum
gdb debugsum
(gdb) break 9                    остановиться перед строкой 9
Breakpoint 1 at ...: file debugsum.c, line 9.
(gdb) run                        запустить программу
Breakpoint 1, main () at debugsum.c:9
9               sum = sum + i;
(gdb) print i                    значение переменной
$1 = 1
(gdb) continue                   выполнять до следующей остановки
(gdb) print i
$2 = 2
(gdb) continue
(gdb) print i
$3 = 3
(gdb) continue
sum = 6                          остановок с i = 4 не было
[Inferior 1 (process ...) exited normally]
(gdb) quit

Вывод gdb здесь сокращён: многоточия и строки после continue убраны. Видно главное: при i = 4 тело не выполнилось — условие i < n не пускает последнее слагаемое. Исправление: i <= n.

КомандаСокращениеЧто делает
break 9, break mainbточка останова на строке или в начале функции
runrзапустить программу
nextnвыполнить текущую строку и остановиться на следующей
print sumpпоказать значение переменной или выражения
display sumпоказывать значение после каждого шага
continuecвыполнять до следующей точки останова
quitqвыйти из отладчика
Те же действия есть в любой IDE — кнопками и мышью: точка останова ставится щелчком слева от номера строки, значения видны в окне переменных. Внутри IDE работает тот же gdb. Командная строка полезна тем, что одинакова везде, в том числе на сервере без графического интерфейса.

Ключевые выводы раздела

Запомните главное

  • Компилятор переводит программу в исполняемый файл заранее; интерпретатор выполняет текст при каждом запуске
  • Сервер, СУБД, интерпретаторы PHP и Python, браузер — программы на C и C++
  • Стандарт курса — C11 (с раздела 20 — C++17); стандарт задаётся ключом -std
  • Команда курса: gcc -std=c11 -Wall -Wextra -pedantic файл.c -o файл, без единого предупреждения
  • Сборка — препроцессор, компилятор, ассемблер, компоновщик; по сообщению видно, на каком этапе ошибка
  • error — exe не создан; warning — создан, но почти наверняка с ошибкой
  • Ошибки исправляются по одной сверху вниз с пересборкой после каждой
  • Отладчик: собрать с -g, поставить точку останова, смотреть переменные
Связи раздела. Опирается на умение работать с файлами и папками в Windows или Linux. Нужен для всех следующих разделов: каждая программа курса собирается и проверяется так, как описано здесь. Этапы сборки понадобятся снова в разделе 18 — программа из нескольких файлов и ошибки компоновщика.
Практическая работа №1 и тест по разделу 1 — на учебном портале. Задания, критерии оценивания и сдача — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Программа курса Раздел 2: Алгоритм и его запись