Что такое int main
Int main C: для чего нужна функция main, прототип в функции Cи
Выражение «int main()» состоит из двух частей:
main() — описание функци.
«Int main()» в С — что это?
Функция main() в С может инициализировать два вида других функций:
функции и методы, написанные разработчиком,
функции и метод ы из стандартных библиотек.
Шаблон программы на С с использованием функции main() выглядит так:
В некоторых случаях код программы может выглядеть вот так:
int main(int argc, char*argv[])
Самая простая программа с использованием функции «main()», которая при помощи стандартной библиотеки выведет нам определенный текст в консоль:
Функция main() имеет свои особенности в С, например:
она не может быть перегружена;
она не может быть объявлена как «inline»;
она не может быть объявлена как «static»;
она не создает адреса;
к ней нельзя обратиться из программы.
Функция «main()» выполняет роль стартера-регулировщика. В программе она выполняет какую-то конкретную задачу. Например:
она может вызывать другие функции, для того чтобы решить поставленную задачу;
она может принимать управление программой, когда какая-либо другая функция за канчивает свою работу;
Заключение
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Несколько подробностей о функции main
Однажды заинтересовался, содержимым стека функции main процесса в linux. Провел некоторые изыскания и теперь представляю вам результат.
Варианты описания функции main:
1. int main()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv[])
5. int main(int argc, char **argv, char **env, char **apple)
argc — число параметров
argv — нуль-терминальный массив указателей на строки параметров командной строки
env — нуль-терминальный массив указателей на строки переменных окружения. Каждая строка в формате ИМЯ=ЗНАЧЕНИЕ
auxv — массив вспомогательных значение (доступно только для PowerPC [1])
apple — путь к исполняемому файлу (в MacOS и Darwin [2])
Вспомогательный вектор — массив с различной дополнительной информацией, такой как эффективный идентификатор пользователя, признак setuid бита, размер страницы памяти и т.п.
Далее о том как получить массив вспомогательных значений для i386 и x86_64, а также об остальном содержимом «сегмента» стека.
Размер сегмента стека можно глянуть в файле maps:
cat /proc/10918/maps
…
7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
…
Перед тем, как загрузчик передаст управление в main, он инициализирует содержимое массивов параметров командной строки, переменных окружения, вспомогательный вектор.
После инициализации верхняя часть стека выглядит примерно так, для 64битной версии.
Старший адрес сверху.
1. | 0x7ffffffff000 | Верхняя точка сегмента стека. Обращение вызывает segfault | |||
0x7ffffffff0f8 | NULL | void* | 8 | 0x00′ | |
2. | filename[0] | char | 1+ | «/tmp/a.out» | |
char | 1 | 0x00 | |||
. | |||||
env[1][0] | char | 1 | 0x00 | ||
. | |||||
char | 1 | 0x00 | |||
3. | 0x7fffffffe5e0 | env[0][0] | char | 1 | .. |
char | 1 | 0x00 | |||
. | |||||
argv[1][0] | char | 1 | 0x00 | ||
. | |||||
char | 1 | 0x00 | |||
4. | 0x7fffffffe5be | argv[0][0] | char | 1+ | «/tmp/a.out» |
5. | Массив случайной длины | ||||
6. | данные для auxv | void*[] | 48′ | ||
AT_NULL | Elf64_auxv_t | 16 | |||
. | |||||
auxv[1] | Elf64_auxv_t | 16 | |||
7. | auxv[0] | Elf64_auxv_t | 16 | Ex.: | |
NULL | void* | 8 | 0x00 | ||
. | |||||
env[1] | char* | 8 | |||
8. | 0x7fffffffe308 | env[0] | char* | 8 | 0x7fffffffe5e0 |
NULL | void* | 8 | 0x00 | ||
. | |||||
argv[1] | char* | 8 | |||
9. | 0x7fffffffe2f8 | argv[0] | char* | 8 | 0x7fffffffe5be |
10. | 0x7fffffffe2f0 | argc | long int | 8′ | число аргументов + 1 |
11. | Локальные переменные и аргументы, функций вызываемых до main | ||||
12. | Локальные переменные main | ||||
13. | 0x7fffffffe1fc | argc | int | 4 | число аргументов + 1 |
0x7fffffffe1f0 | argv | char** | 8 | 0x7fffffffe2f8 | |
0x7fffffffe1e8 | env | char** | 8 | 0x7fffffffe308 | |
14. | Переменные локальных функций |
‘ — описания полей в документах не нашел, но в дампе явно видны.
Для 32 битов не проверял, но скорее всего достаточно только разделить размеры на два.
Вспомогательный вектор
Для i386 и x86_64 нельзя получить адрес первого элемента вспомогательного вектора, однако содержимое этого вектора можно получить другими способами. Один из них — обратиться к области памяти, лежащей сразу за массивом указателей на строки переменных окружения.
Это должно выглядеть примерно так:
Структуры Elf<32,64>_auxv_t описаны в /usr/include/elf.h. Функции заполнения структур в linux-kernel/fs/binfmt_elf.c
Второй способ получить содержимое вектора:
hexdump /proc/self/auxv
Самый удобочитаемое представление получается установкой переменной окружения LD_SHOW_AUXV.
LD_SHOW_AUXV=1 ls
AT_HWCAP: bfebfbff //возможности процессора
AT_PAGESZ: 4096 //размер страницы памяти
AT_CLKTCK: 100 //частота обновления times()
AT_PHDR: 0x400040 //информация о заголовке
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 //адрес интерпретатора, то бишь ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //точка входа в программу
AT_UID: 1000 //идентификаторы пользователя и группы
AT_EUID: 1000 //номинальные и эффективные
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //поднят ли setuid флаг
AT_RANDOM: 0x7fff30bdc809 //адрес 16 случайных байт,
генерируемых при запуске
AT_SYSINFO_EHDR: 0x7fff30bff000 //указатель на страницу, используемую для
//системных вызовов
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
Слева — название переменной, справа значение. Все возможные названия переменных и их описание можно глянуть в файле elf.h. (константы с префиксом AT_)
Возвращение из main()
После инициализации контекста процесса управление передается не в main(), а в функцию _start().
main() вызывает уже из __libc_start_main. Эта последняя функция имеет интересную особенность — ей передается указатель на функцию, которая должна быть выполнена после main(). И указатель этот передается естественно через стек.
Вообще аргументы __libc_start_main имеют вид, согласно файла glibc-2.11/sysdeps/ia64/elf/start.S
/*
* Arguments for __libc_start_main:
* out0: main
* out1: argc
* out2: argv
* out3: init
* out4: fini //функция вызываемая после main
* out5: rtld_fini
* out6: stack_end
*/
Т.е. чтобы получить адрес указателя fini нужно сместиться на два машинных слова от последней локальной переменной main.
Вот что получилось(работоспособность зависит от версии компилятора):
Надеюсь, было интересно.
Удач.
Спасибо пользователю Xeor за полезную наводку.
аргументы Main-Function-и-Command-Line-«> main функции и аргументов командной строки
main Функция не имеет объявления, так как она встроена в язык. Если это так, синтаксис объявления для main будет выглядеть следующим образом:
Стандартные аргументы командной строки
Аргументы для main обеспечения удобного анализа аргументов в командной строке. Типы для параметров argc и argv определяются языком. Имена argc и argv являются традиционными, но их можно называть по своему усмотрению.
Используются следующие определения аргументов.
Сведения о подавлении обработки в командной строке см. в разделе Настройка обработки командной строки C++.
Расширения, относящиеся к Microsoft
В следующих разделах описывается поведение, характерное для Майкрософт.
Как расширение Майкрософт, main w main функции и могут быть объявлены как возвращаемые void (без возвращаемого значения). Это расширение также доступно в некоторых других компиляторах, но его использование не рекомендуется. Он доступен для симметрии, если main не возвращает значение.
main w main Сигнатуры или позволяют дополнительному расширению для доступа к переменным среды, относящимся к Microsoft. это расширение также распространено в других компиляторах для Windows и UNIX систем. Имя envp является традиционным, но вы можете присвоить параметру среды любое имя. Ниже приведены эффективные объявления для списков аргументов, включающих параметр среды:
Main «>примеры аргументов main
В следующем примере показано, как использовать argc аргументы, argv и envp в следующих main случаях:
Анализ аргументов командной строки C++
Правила синтаксического анализа командной строки, используемые кодом Microsoft C/C++, специфичны для Microsoft. Код запуска среды выполнения использует эти правила при интерпретации аргументов, заданных в командной строке операционной системы:
Аргументы разделяются пробелами (пробел или табуляция).
Строка, заключенная в двойные кавычки, интерпретируется как один аргумент, который может содержать пробелы в char актерс. Строку в кавычках можно встроить в аргумент. Курсор ( ^ ) не распознается как escape- char актер или разделитель. Внутри заключенной в кавычки строки пара двойных кавычек интерпретируется как одна экранированная двойная кавычка. Если командная строка заканчивается до тех пор, пока не будет найдена закрывающая двойная кавычка, то все char прочитанные актерс будут выводиться в качестве последнего аргумента.
Символ двойной кавычки после обратной косой черты ( \» ) интерпретируется как литеральный символ двойной кавычки ( « ).
Символы обратной косой черты считаются литералами, если сразу за ними не стоит двойная кавычка.
Если двойная кавычка стоит после четного числа символов обратной косой черты, в массив argv помещается по одному символу обратной косой черты ( \ ) для каждой пары символов обратной косой черты ( \\ ), а сама двойная кавычка ( « ) интерпретируется как разделитель строк.
Пример синтаксического анализа аргументов командной строки
В следующем примере программы показана передача аргументов командной строки:
Результаты синтаксического анализа командных строк
В следующей таблице показаны примеры входных данных и ожидаемые выходные данные, иллюстрирующие применение правил из приведенного выше списка.
Входные данные командной строки | argv [1] | argv [2] | argv 3-5 |
---|---|---|---|
«abc» d e | abc | d | e |
a\\b d»e f»g h | a\\b | de fg | h |
a\\\»b c d | a\»b | c | d |
a\\\\»b c» d e | a\\b c | d | e |
a»b»» c d | ab» c d |
Развертывание подстановочных знаков
Кроме того, компилятор Майкрософт позволяет использовать подстановочныйзнак актерс, вопросительный знак ( ? ) и звездочку ( * ), чтобы указать аргументы filename и Path в командной строке.
Дополнительные сведения о параметрах компоновщика для запуска среды выполнения см. в статье Параметры ссылок.
Настройка обработки командной строки C++
Программа может вызывать семейство подпрограмм spawn или exec в библиотеке среды выполнения C. В этом случае не следует подавлять подпрограмму обработки среды, так как она используется для передачи данных о среде из родительского процесса в дочерний.
Разница между int main () и int main (void)?
что означает следующее:
думаю, что int main() <. >означает, что main не получает никаких параметров (из командной строки), однако:
8 ответов:
В C, разница сомнительна. Некоторые любят утверждать, что последняя версия (без void ) технически является просто общим расширением реализации и не гарантирует работу по стандарту из-за формулировки в стандарте. Однако в стандарте четко указано, что в определении функции пустой набор параметров, имеет четко определенные поведение: что функция не принимает никаких параметров. Таким образом такая определение для main соответствует следующему описанию в стандарте:
Он [main] должен быть определен с возвращаемым типом int и без параметров.
существует, однако, заметная разница между ними: а именно, версия без void не удается предоставить правильный прототип для функции:
О, и просто, чтобы быть полным: void имеет следующее значение во всех деклараторах функций:
(6.7.6.3p10) частный случай неназванного параметра типа void в качестве единственного элемента в списке указывает, что функция не имеет параметров.
В C++ нет никакой разницы, оба одинаково.
прежде всего, есть разница в том, что разрешено для размещенных систем и автономных систем, как показано здесь.
для размещенных систем, 5.1.2.2.1 запуск программы применяется:
функция, вызываемая при запуске программы, называется главным. Реализация объявляет нет прототип для этой функции. Он должен быть определен с типом возврата int и без параметры:
. (далее следует текст что касается стилей argv / argc и т. д.).
интересная часть «без параметров». int main() и int main (void) в настоящее время эквивалентны, так как они оба являются деклараторами функций и не имеют параметров. Применяется следующее (6.7.6.3):
10 частный случай неназванного параметра типа void в качестве единственного элемента в списке указывает, что функция не имеет параметров.
14 список идентификаторов объявляет только идентификаторы параметров функции. пустой список в деклараторе функций, который является частью определения этой функции, указывает, что функция не имеет параметров. пустой список в деклараторе функций, который не является частью определение этой функции указывает, что нет информации о количестве или типах параметров входит в комплект поставки.145)
использование деклараторов функций с пустыми скобками (не деклараторы типа параметров прототип-формат) является устаревшей функцией.
и вот в чем разница. Будучи декларатором функций, int main() и плохой стиль из-за вышеизложенного, так как он не гарантированно работает в следующей версии стандарт C. Он помечается как устаревшая функция в C11.
в C++ обе формы полностью эквивалентны, но есть int main() является предпочтительным стилем по субъективным, косметическим причинам (так говорит Бьярне Страуструп. что, вероятно, является довольно плохим обоснованием для объяснения того, почему вы делаете что-то определенным образом).
Я знаю, что нить старая, но этот вопрос беспокоил меня некоторое время несколько лет назад, поэтому я хотел бросить свои полцента(если это так).
Я всегда рассматриваю функции C, как если бы они имели фиксированное количество аргументов независимо от контекста, если они не используют va_args. То есть, я доверяю main, чтобы всегда иметь прототип:
даже если аргументы не передаются, функция имеет эти аргументы в стеке, потому что основная функция не имеет функции перегрузка.
C имеет возможность иметь примитивную перегрузку, просто притворяясь, что аргумента нет. В этом случае аргумент все еще передается и находится в стеке, но вы никогда не обращаетесь к нему, поэтому он просто уменьшает размер исходного кода.
говоря int main () просто означает, что я знаю, что функция может иметь параметры, но я не использую их, поэтому я пишу int main ().
говоря int main (void) говорит, что main, конечно, не имеет аргументов, и подразумевает, что существуют два разных прототипа функций:
поскольку C не имеет перегрузки функций, это несколько вводит меня в заблуждение, и я не доверяю коду, который имеет main(void) в нем. Я бы не стал, если main никогда не принимал никаких параметров, и в этом случае main(void) будет полностью в порядке.
примечание: в некоторых реализациях есть больше параметров в main, чем argc и argv, таких как env, но это меня не беспокоит, потому что я знаю, что я явно не говорю, что это только два параметра, но это минимальные параметры, и это нормально иметь больше, но не меньше. Это в отличие от прямого высказывания int main (void), которое кричит на меня, поскольку эта функция не имеет параметров, что неверно, поскольку это так, они просто опущены.
вот мой базовый код:
./ пример у меня явно есть аргументы
функция явно имеет аргументы, переданные ей, несмотря на то, чтобы явно сказать, что это не происходит путем ввода void в прототип функции.
(6.7.6.3p10) частный случай неназванного параметра типа void в качестве единственный пункт в списке указывает, что функция не имеет параметров.
таким образом, говоря, что функция имеет void в качестве аргумента, но на самом деле имея аргументы в стеке является противоречием.
моя точка зрения заключается в том, что аргументы все еще существуют, поэтому явно утверждая то, что главное лишено аргументов-это нечестно. Честным способом было бы сказать int main(), который ничего не утверждает о том, сколько параметров у него есть, только о том, сколько параметров вы заботитесь.
NOTE2: _argc, _pargv зависят от системы, чтобы найти свои значения, вы должны найти их, запустив эту программу:
эти значения должны оставаться правильными для вашей конкретной системы.
Функция main и выполнение программ
Все программы, написанные на языке C, содержат основную функцию, которая должна иметь имя main. Если код соответствует модели программирования Юникода, можно использовать версию функции main для многобайтовых символов с именем wmain. Функция main является начальной точкой для выполнения программы. Она обычно управляет выполнением программы, вызывая другие ее функции. Как правило, выполнение программы завершается в конце функции main, но по разным причинам это может случиться и в других местах программы. Иногда (возможно, при обнаружении некоторой ошибки) может потребоваться принудительно завершить программу. Для этого используйте функцию exit. Сведения о функции exit и пример ее использования см. в Справочнике по библиотеке времени выполнения.
Синтаксис
Примечания
Функции в исходном коде программы выполняют одну или несколько конкретных задач. Функция main может вызывать эти функции для выполнения соответствующих задач. Когда функция main вызывает другую функцию, она передает ей управление выполнением, и работа программы продолжается с первого оператора вызываемой функции. Вызываемая функция возвращает управление функции main, когда выполняется оператор или достигается конец этой функции.
Для любой функции, включая функцию main, можно объявить наличие параметров. Термин «параметр» или «формальный параметр» относится к идентификатору, получающему значение, передаваемое функции. Сведения о передаче аргументов в качестве параметров вы найдете в статье Параметры. Когда одна функция вызывает другую, вызываемая функция получает значения своих параметров от вызывающей функции. Эти значения называются аргументами. Для функции main можно объявить формальные параметры, и тогда она будет принимать аргументы из командной строки в следующем формате:
Описание версии main для расширенных символов см. в статье Использование wmain.