Нужно ли int main () объявление на C ++? - PullRequest
61 голосов
/ 01 апреля 2019

Когда я читал о функциях в 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?

Ответы [ 7 ]

61 голосов
/ 01 апреля 2019

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

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

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

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

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

40 голосов
/ 01 апреля 2019

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

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

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

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

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


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

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

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

34 голосов
/ 01 апреля 2019

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

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

25 голосов
/ 01 апреля 2019

Нет, компилятору не требуется предварительное объявление для 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 0; в качестве последнего оператора в теле функции.

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

10 голосов
/ 01 апреля 2019

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

7 голосов
/ 01 апреля 2019

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

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

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) просто представляет записьпункт вашего кода.

5 голосов
/ 01 апреля 2019

Неа. Вы все равно не можете это назвать.

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

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

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

...