Нужно ли int main() объявление для C++?

Когда я читал о функциях в C++, меня учили, что функциям нужно вызывать объявления. Например:

#include <iostream>

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

int sum(int x, int y) {
  return x + y;
}

Возвращает ошибку, так как для функции sum нет объявления.

main.cpp:4:36: error: use of undeclared identifier 'sum'
  std::cout << "The result is " << sum(1, 2);
                                   ^
1 error generated.

Чтобы это исправить, я бы добавил объявление:

#include <iostream>

int sum(int x, int y); // declaration

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

int sum(int x, int y) {
  return x + y;
}

Мой вопрос: почему мы не добавляем объявление для main функции, как мы должны были бы добавить для других функций, таких как sum?

Ответ 1

Определение функции также является объявлением функции.

Цель объявления функции - сделать ее известной компилятору. Объявление функции без ее определения позволяет использовать функцию там, где ее неудобно определять. Например:

  • Если функция используется в исходном файле (A), отличном от того, который определен в (B), нам нужно объявить ее в (обычно через заголовок, который включает в себя A, например, Bh).
  • Если две или более функции могут вызывать друг друга, тогда мы не можем определить все эти функции раньше других - одна из них должна быть первой. Таким образом, декларации могут быть предоставлены в первую очередь, а определения - позже.
  • Многие люди предпочитают помещать подпрограммы "более высокого уровня" ранее в исходный файл, а подпрограммы позже. Поскольку эти подпрограммы "более высокого уровня" вызывают различные подпрограммы, подпрограммы должны быть объявлены ранее.

В C++ пользовательская программа никогда не вызывает main, поэтому ей никогда не требуется объявление перед определением. (Обратите внимание, что вы можете предоставить его, если хотите. В объявлении main нет ничего особенного.) В C программа может вызывать main. В этом случае требуется, чтобы объявление было видимым до вызова.

Обратите внимание, что main должен быть известен коду, который его вызывает. Это специальный код в том, что обычно называется кодом запуска C++. Компоновщик автоматически включает этот код, когда вы связываете программу C++ с соответствующими параметрами компоновщика. Независимо от того, на каком языке написан этот код, он имеет любое объявление main необходимое для правильного вызова.

Ответ 2

Меня учили, что функциям нужны объявления для вызова.

В самом деле. Функция должна быть объявлена до того, как она может быть вызвана.

почему мы не добавляем объявление для main функции?

Ну, вы не вызывали main функцию. На самом деле, вы не должны вызывать main вообще 1 поэтому никогда не нужно объявлять main перед чем-либо.

Хотя технически все определения также являются декларациями, поэтому ваше определение main также объявляет main.


Сноска 1: Стандарт C++ гласит, что вызывать main из программы не определено.

Это позволяет реализациям C++ поместить специальный стартовый код однократного запуска в начало основного, если они не могут запустить его раньше из-за перехватов в коде запуска, который обычно вызывает main. Некоторые реальные реализации фактически делают это, например, вызывая функцию быстрой математики, которая устанавливает некоторые флаги FPU, такие как denormals-are-zero.

В гипотетической реализации вызов main может привести к таким забавным вещам, как повторный запуск конструкторов для всех статических переменных, повторная инициализация структур данных, используемых new/delete для отслеживания распределений, или другой полный сбой вашей программы. Или это может не вызвать никаких проблем. Неопределенное поведение не означает, что оно должно терпеть неудачу в каждой реализации.

Ответ 3

Прототип необходим, если вы хотите вызвать функцию, но она еще не доступна, как sum в вашем случае.

Вы не должны вызывать main самостоятельно, поэтому вам не нужно иметь прототип. Это даже плохая идея написать прототип.

Ответ 4

Нет, компилятору не требуется предварительное объявление для main().

main() является специальной функцией в C++.

Некоторые важные вещи, которые нужно помнить о main():

  1. Компоновщик требует, чтобы при создании исполняемой программы существовала одна и только одна функция main().
  2. Компилятор ожидает функцию main() в одной из следующих двух форм:
int main () { /* body */ } 
int main (int argc, char *argv[]) { /* body */ } 

где body ноль или более операторов

Дополнительная приемлемая форма зависит от реализации и предоставляет список переменных среды во время вызова функции:

int main (int argc, char* argv[], char *envp[]) { /* body */ }

Кодировщик должен предоставить "определение" main, используя одну из этих приемлемых форм, но кодировщик не должен предоставлять декларацию. Кодированное определение принимается компилятором как объявление main().

  1. Если оператор return не предоставлен, компилятор выдаст return 0; как последнее утверждение в теле функции.

Кроме того, иногда возникает путаница относительно того, может ли программа C++ вызвать функцию main(). Это не рекомендуется. В проекте C++ 17 говорится, что main() "не должен использоваться в программе". Другими словами, не может быть вызван из программы. См., Например, рабочий проект стандарта для языка программирования C++ от "2017-03-21", пункт 6.6.1.3, стр. 66. Я понимаю, что некоторые компиляторы поддерживают это (включая мой), но следующая версия компилятора может изменить или удалить это поведение, так как стандарт использует термин "не будет".

Ответ 5

Недопустимо вызывать main изнутри вашей программы. Это означает, что единственное, что будет вызывать его, - это среда выполнения, и компилятор/компоновщик может обработать его настройку. Это означает, что вам не нужен прототип для main.

Ответ 6

Определение функции также неявно объявляет ее. Если вам нужно ссылаться на функцию до ее определения, вам нужно объявить ее перед использованием.

Таким образом, написание следующего также допустимо:

int sum(int x, int y) {
  return x + y;
}

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

Если вы используете объявление в одном файле, чтобы сделать функцию известной компилятору до ее определения, то ее определение должно быть известно во время компоновки:

main.cpp

int sum(int x, int y);

int main() {
  std::cout << "The result is " << sum(1, 2);
  return 0;
}

sum.cpp

int sum(int x, int y) {
  return x + y;
}

Или sum может иметь свое происхождение в библиотеке, так что вы даже не скомпилируете ее самостоятельно.

Функция main нигде не используется/не упоминается в вашем коде, поэтому нет необходимости добавлять объявление main любом месте.

До и после вашей main функции библиотека c++ может выполнить некоторые шаги инициализации и очистки и вызвать вашу main функцию. Если эта часть библиотеки будет представлена как код c++, то она будет содержать объявление int main(), чтобы ее можно было скомпилировать. Этот код может выглядеть так:

int main();

int __main() {
  __startup_runtime();

  main();

  __cleanup_runtime();
}

Но затем у вас снова возникает та же проблема с __main поэтому в какой-то момент c++ больше нет, и определенная функция (main) просто представляет точку входа в ваш код.

Ответ 7

Нету. Вы не можете назвать это так или иначе.

Предварительные объявления нужны только для функций, вызываемых до их определения. Для функций, определенных в других файлах, вам нужны внешние объявления (которые выглядят точно так же, как и предварительные объявления).

Но вы не можете позвонить по main в C++, поэтому он вам не нужен. Это потому, что компилятору C++ разрешено изменять main для выполнения глобальной инициализации.

[Я посмотрел на crt0.c, и у него есть объявление для main, но это ни здесь, ни там].

Ответ 8

Я считаю, что это квест Linking. Линкер найдет main и назначит свой адрес последовательности загрузки программы. Вот почему main() не нужно объявлять: потому что это точка входа в программу, адрес которой уже найден и размещен компоновщиком.

Ответ 9

Ни один из ответов здесь фактически не касается вопроса. Базовый код, который всегда компилируется без вашего ведома, если вы не указали компилятору специально, является начальным набором функций времени выполнения в файле, который иногда называется _crt0. Это включает в себя две важные функции: запуск и выход. Именно здесь определяется главное.

В отсутствие каких-либо интересных вещей, main в начале называется так:

Выход (основной (арг));

Однако start и exit отвечают за инициализацию, особенно в C++. exit отвечает за их уничтожение.

Поэтому нам нужно main, потому что _crt0 нуждается в main. Вот почему компоновщик выдает ошибку, если у вас ее нет - SOMETHING вызывает main, то есть start.

Это также неправда, что вы не можете назвать основной. Main - это просто функция, и ее можно вызывать так же, как и любую другую. Тот факт, что мы склонны не вызывать main, является всего лишь артефактом идеи, что main является "точкой входа" в нашу программу, поэтому вызов main дважды или более раз в основном перезапустил бы вещи. Тем не менее, можно написать рекурсивную основную функцию, если они того пожелают, чтобы иметь законное условие завершения. Это странно, но это не неопределенное поведение.

Ответ 10

Основная функция не является определяемой пользователем функцией.

Вам нужно объявление функции для пользовательских функций.

Проверьте документы: C++/Основная функция