Различные соглашения для main () в C

Мое единственное воздействие на программирование было Java, где я не встречал (до сих пор) разных соглашений для написания основного метода. Я следил за источниками обучения c (K & R AND C Programming A Modern Approach), где они используют очень разные формы основного метода (функции).

Версия K & R до сих пор:

main() { blah blah blah; } 

C Программирование Современный подход

 int main() { blah blah blah; return 0; } 

ИЛИ ЖЕ

 int main() { blah blah blah; //returns nothing } 

Чтобы сделать вещи более запутанными, я видел людей:

 int main(void) { blah blah blah; } 

в то время как они либо вернулись 0, либо нет. Я не в своем необразованном предположении думаю, что это только проблема стандартов, но, возможно, нечто более концептуальное или глубокое. Может ли кто-то пролить свет на эту проблему?

  • Стиль K & R устарел и не соответствует правильному стандарту C.

  • Подлинные подписи

     int main(void) 

    а также

     int main(int argc, char *argv[]) 

    или, что эквивалентно, потому что тип массива в функции всегда настроен на тип указателя:

     int main(int argc, char **argv) 
  • Подпись

     int main() 

    также является действительным, поскольку пустой список аргументов означает любое количество аргументов, которые не описаны *). AFAIK, это может быть изменено, поэтому не пишите так. Письмо void – это то, как вы выражаете эту функцию, не принимает аргументов в C.

  • Реализации C могут предоставлять другие точки ввода, определенные реализацией . Но перечисленные выше два являются единственными, гарантированными стандартом.

  • В C99 было введено специальное правило для main() которое указывает, что функция не возвращает ничего, значение 0 возвращается неявно. Поэтому только в основном вы можете пропустить return . Мой совет: не надо. Это просто сбивает с толку. Но это мнение.


*) Обратите внимание, что это отличается в C ++, где ничто между скобками не означает: никаких аргументов.

Предварительно стандартизированные версии C (известные как K & R C) имели концепцию типа int по умолчанию, если ни один не был дан. Итак, в K & R это:

 main() { 

Такой же как:

 int main() { 

Что касается разности между int main() и int main(void) , пустой список параметров означает, что функция принимает неопределенное количество параметров, а (void) в качестве списка параметров означает, что функция не принимает никаких параметров. Первый является приемлемым, но последний предпочтительнее, поскольку он более ясен.

Что касается использования оператора return , функция с не-void возвращаемым типом должна использовать return для возврата значения, за исключением (начиная со стандартного C99) для main функции. В случае main , отсутствующий оператор return подразумевает возвращаемое значение 0.

Поскольку неявный return 0 для main был добавлен в C99, вы увидите некоторый код, который явно возвращает, и некоторые, которые не зависят от того, какая версия стандарта соответствует программисту.

Существует два стандартных подписи для main из последних стандартов языка C:

 int main( void ) // void indicates "takes no arguments" 

а также

 int main( int argc, char *argv[] ) // or char **argv, it means the same thing in this context 

Имена argc и argv являются произвольными; вы можете использовать разные имена, если хотите.

Реализации могут предоставлять дополнительные действительные сигнатуры для main – проверьте вашу документацию компилятора.

Если ваша программа не принимает аргументы командной строки, используйте первую форму, иначе используйте вторую.

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

Неявный ввод текста

Прежде всего, C первоначально допускал неявные объявления int – если компилятор видел определение функции или объявление без спецификатора типа, он предположил, что функция возвратила int :

 foo(); // modern equivalent: int foo( void ) 

Это было разрешено вплоть до стандарта 1999 года, хотя большинство из нас было задолго до этого считалось плохим.

Ключевое слово void не было введено до стандарта 1989 года. В качестве спецификатора типа он указывает тип без значений. В качестве идентификатора в списке параметров функции он указывает, что функция не принимает аргументов.

Перед введением ключевого слова void не было никакого хорошего способа (кроме документации), чтобы отличать функции, которые возвращали значение, которое вы должны использовать против функций, которые только что выполнили какое-либо действие. Некоторые из нас использовали термин «неявный int », чтобы указать, что эти функции не предназначены для возврата чего-либо значимого:

 foo(); /* returns int, but return value not meant to be used */ int bar(); /* returns int, return value meant to be used */ 

Опять же, это была просто конвенция и далека от всеобщей. Теперь мы будем использовать ключевое слово void :

 void foo(); /* does not return a value */ int bar(); /* returns int */ 

Синтаксис прототипа функции

Первоначально определение функции выглядело примерно так:

 foo( bar, bletch, blurga ) int bar; double bletch; char *blurga; { /* function body */ } 

В списке параметров указаны только имена параметров, а не их типы; это было сделано в отдельном наборе объявлений между декларатором функции и открытием { тела функции. Функция, которая не принимала аргументов, имела пустой список идентификаторов в определении функции:

 blah( ) { /* function body */ } 

В декларациях функций указано только имя и тип возвращаемого значения функции; он вообще не указывал параметры:

 foo( ); /* no bar, bletch, or blurga */ 

Пустой список идентификаторов в объявлении функции указывает, что функция принимает неопределенное количество аргументов, а не нулевые аргументы. Компилятор мог проверить правильность использования возвращаемого типа вызова функции, но он не мог проверить правильность числа и типов параметров в вызове.

В стандарте 1989 года введено понятие синтаксиса прототипа функции, в котором тип каждого параметра был указан вместе с его именем в списке параметров:

 foo( int bar, double bletch, char *blurga ) { /* function body */ } 

Это применимо как к объявлению функции, так и к определению:

 foo( int bar, double bletch, char *blurga ); 

Это изменение позволило компилятору проверить правильность числа и типов параметров в вызове функции вместе с типом возврата. Кроме того, ключевое слово void можно использовать в списке параметров, чтобы указать, что функция не принимала никаких параметров в определении и декларации:

 blah( void ); /* declaration, returns int, takes no parameters */ blah( void ) /* definition */ { /* function body */ } 

Так что да, в зависимости от того, с какой версией языка вы работаете, main будет написано по-другому:

К & Р:

 main() main( argc, argv ) { int argc; ... char *argv[]; } { ... } 

C89:

 main( void ) main( int argc, char *argv[] ) { { ... ... } } 

C99 и выше:

 int main( void ) int main( int argc, char *argv[] ) { { ... ... } } 

Стандарт C определяет подпись для main либо как

 int main(void) 

или же

 int main(int argc, char *argv[]) 

Добавление return 0; поскольку последнее утверждение в main функции является необязательным.
Стандарт также говорит о некотором прототипе, определенном для реализации. int main() принимается компилятором GCC .

main() – старый прототип школы и почти не рекомендуется.