Каковы действительные подписи для функции main () в C? - PullRequest
56 голосов
/ 21 января 2010

Каковы действительные подписи для основной функции в C? Я знаю:

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

Есть ли другие действительные?

Ответы [ 5 ]

65 голосов
/ 21 января 2010

Нынешний стандарт на момент этого ответа (C11) явно упоминает эти два:

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

хотя в нем упоминается фраза «или эквивалент» со следующей сноской:

Таким образом, int можно заменить на имя typedef, определенное как int, или тип argv можно записать как char ** argv и т. Д.

Кроме того, он также предоставляет дополнительные (определяемые реализацией) возможности.

В соответствующем разделе (раздел 5.1.2.2.1 раздела C11, но этот конкретный аспект не отличается от C99) говорится:

Функция, вызываемая при запуске программы, называется main. Реализация не объявляет прототип для этой функции. Он должен быть определен с типом возврата int и без параметров:

int main(void) { /* ... */ }

или с двумя параметрами (именуемыми здесь argc и argv, хотя могут использоваться любые имена, поскольку они являются локальными для функции, в которой они объявлены):

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

или эквивалентный; или другим способом, определяемым реализацией.

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

  • Значение argc должно быть неотрицательным.

  • argv[argc] должен быть нулевым указателем.

  • Если значение argc больше нуля, элементы массива с argv[0] по argv[argc-1] включительно должны содержать указатели на строки, которым перед запуском программы передаются определяемые реализацией значения средой хоста , Намерение состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другого места в размещенной среде. Если среда хоста не может предоставлять строки с буквами как в верхнем, так и в нижнем регистре, реализация должна обеспечить получение строк в нижнем регистре.

  • Если значение argc больше нуля, строка, на которую указывает argv[0], представляет имя программы; argv[0][0] должен быть нулевым символом, если имя программы недоступно из среды хоста. Если значение argc больше единицы, строки, на которые указывают argv[1] - argv[argc-1], представляют параметры программы.

  • Параметры argc и argv и строки, на которые указывает массив argv, должны изменяться программой и сохранять свои последние сохраненные значения между запуском программы и ее завершением.

Обратите внимание, что это для размещенной среды, которую вы обычно видите в программах на Си. Автономная среда (такая как встроенная система) гораздо менее ограничена, как указано в 5.1.2.1 того же стандарта:

В автономной среде (в которой выполнение программы на С может осуществляться без какой-либо выгоды от операционной системы), имя и тип функции, вызываемой при запуске программы, определяются реализацией. Любые библиотечные средства, доступные для автономной программы, кроме минимального набора, требуемого пунктом 4, определяются реализацией.

16 голосов
/ 25 ноября 2010

Стандарт С

Для размещенной среды (это нормальная среда) стандарт C99 гласит:

5.1.2.2.1 Запуск программы

Функция, вызываемая при запуске программы, называется main. Реализация заявляет нет прототип для этой функции. Он должен быть определен с типом возврата int и без Параметры:

int main(void) { /* ... */ }

или с двумя параметрами (именуемыми здесь argc и argv, хотя любые имена могут быть используется, поскольку они являются локальными для функции, в которой они объявлены):

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

или эквивалентный; 9) или другим способом, определяемым реализацией.

9) Таким образом, int может быть заменено именем typedef, определенным как int, или тип argv может быть записан как char **argv и т. Д.

Стандарты C11 и C18 в основном соответствуют стандарту C99.

Стандарт С ++

Стандарт C ++ 98 гласит:

3.6.1 Основная функция [basic.start.main]

1 Программа должна содержать глобальную функцию main, которая является назначенным началом программы. [...]

2 Реализация не должна предопределять основную функцию. Эта функция не должна быть перегружена. Это должно иметь тип возвращаемого значения типа int, но в противном случае его тип определяется реализацией. Все реализации должно допускать оба следующих определения основных:

int main() { /* ... */ }

и

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

Стандарт C ++ прямо говорит: «Он [основная функция] должен иметь тип возвращаемого значения типа int, но в противном случае его тип определяется реализацией», и для него требуются те же две подписи, что и для стандарта C. Таким образом, void main () напрямую не разрешен стандартом C ++, хотя он ничего не может сделать, чтобы мешать нестандартной соответствующей реализации не допускать альтернативы (ни стандартной соответствующей реализации не разрешать альтернативы в качестве расширений стандарта).

Стандарты C ++ 03, C ++ 11, C ++ 14 и C ++ 17, по сути, совпадают с C ++ 98.

Общее расширение

Классически системы Unix поддерживают третий вариант:

int main(int argc, char **argv, char **envp) { ... }

Третий аргумент - это список указателей на строки с нулевым символом в конце, каждый из которых является переменной окружения, которая имеет имя, знак равенства и значение (возможно, пустое). Если вы не используете это, вы все равно можете попасть в окружение через 'extern char **environ;'. Долгое время у этого не было заголовка, который объявил его, но стандарт POSIX 2008 теперь требует, чтобы он был объявлен в <unistd.h>.

Это признано стандартом C как общее расширение, документированное в Приложении J:

J.5.1 Аргументы среды

¶1 В размещенной среде главная функция получает третий аргумент, char *envp[], который указывает на массив указателей с нулевым символом в конце на char, каждый из которых указывает на строку который предоставляет информацию о среде для выполнения программы (5.1.2.2.1).

Microsoft C

Компилятор Microsoft VS 2010 интересен. На сайте написано:

Синтаксис объявления для main:

 int main();

или, необязательно,

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

В качестве альтернативы функции main и wmain могут быть объявлены как возвращающие void (без возвращаемого значения). Если вы объявляете main или wmain как возвращающие void, вы не можете вернуть код завершения родительскому процессу или операционной системе с помощью оператора return. Чтобы вернуть код выхода, когда main или wmain объявлен как void, необходимо использовать функцию exit.

Мне не ясно, что происходит (какой код завершения возвращается родителю или o / s), когда программа с void main() завершает работу - и веб-сайт MS тоже молчит.

Интересно, что MS не предписывает версию main() с двумя аргументами, которая требуется для стандартов C и C ++. Он только предписывает форму с тремя аргументами, где третий аргумент - char **envp, указатель на список переменных среды.

На странице Microsoft также перечислены некоторые другие альтернативы - wmain(), который принимает строки широких символов, и некоторые другие.

Microsoft VS 2005 версия на этой странице не перечисляет void main() в качестве альтернативы. версии от Microsoft VS 2008 года и старше.

Является ли int main() таким же, как int main(void)?

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

В Си есть разница между двумя обозначениями, но вы замечаете это только в эзотерических случаях. В частности, есть разница, если вы вызываете функцию main() из своего собственного кода, что вам разрешено делать в C и не разрешено делать в C ++.

Запись int main() не предоставляет прототип для main(), но это имеет значение, только если вы вызываете его рекурсивно. С int main() вы могли бы позже (в той же функции или в другой функции) написать int rc = main("absolute", "twaddle", 2):, и формально компилятор не должен жаловаться на степень отказа в компиляции кода, хотя он может обоснованно жаловаться (предупреждаю) об этом (и использование -Werror с GCC превратит предупреждение в ошибку). Если вы используете int main(void), последующий вызов main() должен выдать ошибку - вы сказали, что функция не принимает аргументов, но попытались предоставить три. Конечно, вы не можете законно вызвать main() до того, как объявите или определили его (если только вы не используете семантику C90) - и реализация не объявляет прототип для main(). NB. Стандарт C11 иллюстрирует как int main(), так и int main(void) в разных примерах - оба действительны в C, хотя между ними есть небольшая разница.

8 голосов
/ 21 января 2010

http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B

Помимо обычных int main(int argc, char *argv[]) и POSIX int main(int argc, char **argv, char **envp), в Mac OS X также поддерживается

int main(int argc, char* argv[], char* envp[], char* apple[]);

Конечно, это только для Mac.

В Windows

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

как вариант Unicode (на самом деле, широкий символ). Конечно, есть WinMain тоже.

8 голосов
/ 21 января 2010

POSIX поддерживает <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/execve.2.html" rel="noreferrer">execve()</a>, что в свою очередь поддерживает

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

Добавленный аргумент - это среда, т. Е. Массив строк вида NAME = VALUE.

3 голосов
/ 21 января 2010
int main(void)

Под некоторыми ОС (например, Windows) также действует:

int main(int argc, char **argv, char **envp)

где envp - среда, в противном случае доступная через getenv()

...