main — это функция, с которой операционная система начинает выполнение программы на C или C++ (точка входа). Стандарт определяет для нее ровно две переносимые формы: int main(void) без аргументов и int main(int argc, char *argv[]) с аргументами командной строки. Разберем обе сигнатуры, что означает возвращаемое значение, как устроены argc и argv, где C и C++ ведут себя по-разному. Код ниже собран компилятором и запущен, вывод приведен как есть.
Содержание
Минимальный рабочий пример
Самая короткая программа на C++, которую можно скомпилировать и запустить, выглядит так:
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
Вывод в консоль:
Hello, World!
Разберем по строкам. #include <iostream> подключает заголовок стандартной библиотеки для потоков ввода-вывода. int перед main — тип возвращаемого значения: функция вернет операционной системе целое число. std::cout — стандартный поток вывода, std:: указывает на пространство имен стандартной библиотеки. return 0 сообщает системе, что программа завершилась без ошибок.
Тело функции — это то, что между фигурными скобками { и }. До main, в начале файла, обычно стоят только директивы #include и объявления.
Допустимые сигнатуры
Стандарт C и C++ гарантирует переносимость двух форм: без параметров и с параметрами командной строки. Остальные записи либо специфичны для платформы, либо просто ошибочны. Сведем это в таблицу.
| Сигнатура | C | C++ | Смысл |
|---|---|---|---|
int main(void) |
да | да | без аргументов; в C (void) явно говорит «параметров нет» |
int main() |
зависит от версии | да | в C++ то же, что (void); в C до C23 означало «список параметров не задан», с C23 — тоже «нет параметров» |
int main(int argc, char *argv[]) |
да | да | с аргументами командной строки |
int main(int argc, char **argv) |
да | да | та же форма, другая запись массива указателей |
void main() |
нестандартно | нестандартно | не по стандарту, переносимости нет |
Реализация может поддерживать и дополнительные формы (например, третий параметр с переменными окружения), но на них полагаться нельзя: это расширение конкретного компилятора, а не требование стандарта.
Что возвращает main и зачем
Тип int перед main — это код завершения, который получает операционная система или вызвавший процесс. По соглашению 0 означает успешное завершение, ненулевое значение — ошибку. Чтобы не привязываться к конкретным числам, в <stdlib.h> (в C++ — <cstdlib>) определены макросы EXIT_SUCCESS и EXIT_FAILURE.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("Gotovo\n");
return EXIT_SUCCESS;
}
Вывод и код возврата:
Gotovo
Программа завершилась с кодом 0. Проверить его в оболочке можно командой echo $? сразу после запуска.
Здесь есть важное различие между языками. В C++ return в main можно не писать: если управление дошло до закрывающей скобки, компилятор сам подставит return 0. В C то же поведение гарантировано стандартом начиная с C99. Пример на C++ без return:
#include <iostream>
int main() {
std::cout << "Bez return" << std::endl;
}
Вывод:
Bez return
Код возврата все равно 0, хотя return мы не писали. Это работает только для main: любая другая функция с типом int обязана возвращать значение явно.
argc и argv: аргументы командной строки
Вторая форма main принимает то, что пользователь передал программе при запуске. argc (argument count) — число аргументов, argv (argument vector) — массив строк с самими аргументами. Важная деталь: argv[0] — это имя, под которым запустили программу, поэтому argc всегда не меньше 1, а собственно параметры начинаются с argv[1].
#include <iostream>
int main(int argc, char *argv[]) {
std::cout << "Vsego argumentov: " << argc << std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << "argv[" << i << "] = " << argv[i] << std::endl;
}
return 0;
}
Запуск с аргументами file.txt -v 42 дает такой вывод:
Vsego argumentov: 4
argv[0] = ./args
argv[1] = file.txt
argv[2] = -v
argv[3] = 42
argc равен 4: имя программы плюс три переданных слова. Элемент argv[argc] по стандарту равен нулевому указателю, так что массив можно обходить и до NULL, но опираться удобнее на argc.
Разбор аргументов: превращаем строку в число
argv — это всегда строки, даже если пользователь ввел цифры. Чтобы получить число, строку нужно разобрать: в C для этого есть strtol. Заодно покажем, как проверять, что аргументов передали столько, сколько нужно, и завершаться с ошибкой, если нет.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Ozhidayu 2 chisla, poluchil %d\n", argc - 1);
return EXIT_FAILURE;
}
long a = strtol(argv[1], NULL, 10);
long b = strtol(argv[2], NULL, 10);
printf("%ld + %ld = %ld\n", a, b, a + b);
return EXIT_SUCCESS;
}
При правильном вызове с двумя числами:
2 + 3 = 5
Код возврата 0. А если чисел не хватает, программа пишет в поток ошибок и завершается с ненулевым кодом:
Ozhidayu 2 chisla, poluchil 1
Код возврата 1 (EXIT_FAILURE). Такой контракт «нет аргументов — ошибка» и позволяет другим программам и скриптам понимать, отработала ли ваша утилита.
Типичная ошибка: void main
Иногда в старых учебниках встречается запись void main(). Она не соответствует стандарту ни C, ни C++, и современный компилятор на нее ругается. Неверный вариант:
#include <stdio.h>
void main(void) {
printf("void main\n");
}
Фактический результат сборки (Apple Clang 21):
error: 'main' must return 'int'
Исправление — вернуть тип int и код завершения:
#include <stdio.h>
int main(void) {
printf("Vernyj main\n");
return 0;
}
Строгость реакции зависит от компилятора: часть тулчейнов выдает предупреждение, а не ошибку, и молча собирает такой код. Именно поэтому новичок легко пропускает проблему. Правило простое: main всегда возвращает int.
В чем C и C++ расходятся
Формы сигнатур в двух языках совпадают, но есть нюансы, которые стоит держать в голове.
int main()в C++ строго означает «нет параметров». В C до стандарта C23 пустые скобки означали «список параметров не указан», а не «параметров нет»; чтобы явно сказать «без аргументов», в C пишутint main(void).- Отсутствие
returnвmainв C++ было легально всегда, в C — начиная с C99. - Тип возврата и общий смысл
argc/argvв обоих языках одинаковы, поэтому базовые примеры переносятся между C и C++ почти без изменений.
Выводы
- main — точка входа программы на C и C++; переносимых сигнатур две:
int main(void)иint main(int argc, char *argv[]). - Возвращаемое значение — код завершения для ОС:
0(илиEXIT_SUCCESS) — успех, ненулевое (EXIT_FAILURE) — ошибка. - В C++
returnвmainможно опустить, компилятор подставитreturn 0; в C это гарантировано с C99. argc— число аргументов (минимум 1),argv[0]— имя программы, реальные параметры идут сargv[1]; строки изargvразбираются функциями вродеstrtol.void main— не по стандарту; всегда используйте типint.
Где применяется / связь с практикой
Освойте тему на практике
Правильно оформленная main и разбор argc/argv — это основа любых консольных утилит: от учебных до системных инструментов, которые принимают флаги и пути к файлам. На них же строятся коды возврата, по которым автотесты и скрипты сборки понимают, прошла ли программа. Разобраться с этим на практике, писать код и получать разбор от преподавателя удобнее в структурированном курсе — например, на курсе «C++ Basic» в Otus. Посмотреть формат занятий и темы можно на открытых уроках Otus — они бесплатные и проходят регулярно.
FAQ
Может ли main вызывать сама себя или другая функция вызвать main?
В C++ вызывать main из кода программы запрещено стандартом. В C это формально не запрещено, но так почти никогда не делают: это точка входа, а не обычная функция для рекурсии.
Чем main отличается в С++ от функций, у которых нельзя опустить return?
Право не писать return — особый случай именно для main. Любая другая функция с типом int при отсутствии return дает неопределенное поведение, поэтому значение нужно возвращать явно.
Почему argv имеет тип char *argv[], а не просто строку?
Это массив указателей на строки: каждый аргумент — отдельная C-строка, а argv хранит адреса их начал. Запись char *argv[] и char **argv означают одно и то же.



