При создании консольного приложения в языке программирования С++, автоматически создается строка очень похожая на эту:
Int main(int argc, char* argv) // параметры функции main()
Эта строка — заголовок главной функции main() , в скобочках объявлены параметры argс и argv. Так вот, если программу запускать через командную строку, то существует возможность передать какую-либо информацию этой программе, для этого и существуют параметры argc и argv . Параметр argc имеет тип данных int , и содержит количество параметров, передаваемых в функцию main . Причем argc всегда не меньше 1, даже когда мы не передаем никакой информации, так как первым параметром считается имя функции. Параметр argv это массив указателей на строки. Через командную строку можно передать только данные строкового типа. Указатели и строки — это две большие темы, под которые созданы отдельные разделы. Так вот именно через параметр argv и передается какая-либо информация. Разработаем программу, которую будем запускать через командную строку Windows, и передавать ей некоторую информацию.
// argc_argv.cpp: определяет точку входа для консольного приложения.
#include "stdafx.h"
#include // код Code::Blocks // код Dev-C++ // argc_argv.cpp: определяет точку входа для консольного приложения.
#include После того как отладили программу, открываем командную строку Windows и перетаскиваем в окно командной строки экзэшник нашей программы, в командной строке отобразится полный путь к программе(но можно прописать путь к программе в ручную), после этого можно нажимать ENTER
и программа запустится (см. Рисунок 1). Рисунок 1 — Параметры функции main Так как мы просто запустили программу и не передавали ей никаких аргументов, появилось сообщение Not arguments . На рисунке 2 изображён запуск этой же программы через командную строку, но уже с передачей ей аргумента Open . Рисунок 2 — Параметры функции main Аргументом является слово Open , как видно из рисунка, это слово появилось на экране. Передавать можно несколько параметров сразу, отделяя их между собой запятой. Если необходимо передать параметр состоящий из нескольких слов, то их необходимо взять в двойные кавычки, и тогда эти слова будут считаться как один параметр. Например, на рисунке изображен запуск программы, с передачей ей аргумента, состоящего из двух слов — It work . Рисунок 3 — Параметры функции main А если убрать кавычки. То увидим только слово It . Если не планируется передавать какую-либо информацию при запуске программы, то можно удалить аргументы в функции main() , также можно менять имена данных аргументов. Иногда встречается модификации параметров argc и argv , но это все зависит от типа создаваемого приложения или от среды разработки. Иногда при запуске программы бывает полезно передать ей какую-либо информацию. Обычно такая информация передается функции main() с помощью аргументов командной строки. Аргумент командной строки
- это информация, которая вводится в командной строке операционной системы вслед за именем программы. Например, чтобы запустить компиляцию программы, необходимо в командной строке после подсказки набрать примерно следующее: Cc имя_программы
имя_программы
представляет собой аргумент командной строки, он указывает имя той программы, которую вы собираетесь компилировать. Чтобы принять аргументы командной строки, используются два специальных встроенных аргумента: argc и argv . Параметр argc содержит количество аргументов в командной строке и является целым числом, причем он всегда не меньше 1, потому что первым аргументом считается имя программы. А параметр argv является указателем на массив указателей на строки. В этом массиве каждый элемент указывает на какой-либо аргумент командной строки. Все аргументы командной строки являются строковыми, поэтому преобразование каких бы то ни было чисел в нужный двоичный формат должно быть предусмотрено в программе при ее разработке. Вот простой пример использования аргумента командной строки. На экран выводятся слово Привет и ваше имя, которое надо указать в виде аргумента командной строки.
#include Если вы назвали эту программу name (имя) и ваше имя Том, то для запуска программы следует в командную строку ввести name Том. В результате выполнения программы на экране появится сообщение Привет, Том. Во многих средах все аргументы командной строки необходимо отделять друг от друга пробелом или табуляцией. Запятые, точки с запятой и тому подобные символы разделителями не считаются. Например, Run Spot, run
состоит из трех символьных строк, в то время как Эрик, Рик, Фред
представляет собой одну символьную строку - запятые, как правило, разделителями не считаются. Если в строке имеются пробелы, то, чтобы из нее не получилось несколько аргументов, в некоторых средах эту строку можно заключать в двойные кавычки. В результате вся строка будет считаться одним аргументом. Чтобы подробнее узнать, как в вашей операционной системе задаются параметры командной строки, изучите документацию этой системы. Очень важно правильно объявлять argv . Вот как это делают чаще всего: Char *argv;
Пустые квадратные скобки указывают на то, что у массива неопределенная длина. Теперь получить доступ к отдельным аргументам можно с помощью индексации массива argv . Например, argv указывает на первую символьную строку, которой всегда является имя программы; argv указывает на первый аргумент и так далее. Другим небольшим примером использования аргументов командной строки является приведенная далее программа countdown (счет в обратном порядке). Эта программа считает в обратном порядке, начиная с какого-либо значения (указанного в командной строке), и подает звуковой сигнал, когда доходит до 0. Обратите внимание, что первый аргумент, содержащий начальное значение, преобразуется в целое значение с помощью стандартной функции atoi() . Если вторым аргументом командной строки (а если считать аргументом имя программы, то третьим) является строка «display» (вывод на экран), то результат отсчета (в обратном порядке) будет выводиться на экран.
/* Программа счета в обратном порядке. */
#include Обратите внимание, если аргументы командной строки не будут указаны, то будет выведено сообщение об ошибке. В программах с аргументами командной строки часто делается следующее: в случае, когда пользователь запускает эти программы без ввода нужной информации, выводятся инструкции о том, как правильно указывать аргументы. Чтобы получить доступ к отдельному символу одного из аргументов командной строки, введите в argv второй индекс. Например, следующая программа посимвольно выводит все аргументы, с которыми ее вызвали:
#include Помните, первый индекс argv обеспечивает доступ к строке, а второй индекс - доступ к ее отдельным символам. Обычно argc и argv используют для того, чтобы передать программе начальные команды, которые понадобятся ей при запуске. Например, аргументы командной строки часто указывают такие данные, как имя файла, параметр или альтернативное поведение. Использование аргументов командной строки придает вашей программе «профессиональный внешний вид» и облегчает ее использование в пакетных файлах. Имена argc и argv являются традиционными, но не обязательными. Эти два параметра в функции main() вы можете назвать как угодно. Кроме того, в некоторых компиляторах для main() могут поддерживаться-дополнительные аргументы, поэтому обязательно изучите документацию к вашему компилятору. Когда для программы не требуются параметры командной строки, то чаще всего явно декларируют функцию main() как не имеющую параметров. В таком случае в списке параметров этой функции используют ключевое слово void . Теги: Параметры командной строки
С
и - компилируемый язык. После сборки программа представляет собой исполняемый файл (мы не рассматриваем создание динамических библиотек,
драйверов и т.д.). Наши программы очень простые и не содержат библиотек времени выполнения (Runtime libraries), поэтому могут быть перенесены на компьютер с такой же
операционной системой (и подобной архитектурой) и там запущены. Программа во время запуска может принимать параметры. Они являются аргументами функции main.
Общий вид функции main следующий Void main(int argc, char **argv) {
...
}
Первым аргументом argc является число переданных функции параметров. Второй аргумент – массив строк – собственно сами параметры. Так как параметры у функции могут
быть любыми, то они передаются как строки, и уже сама программа должна их разбирать и приводить к нужному типу. Первым аргументом (argv) всегда является имя программы. При этом имя выводится в зависимости от того, откуда была запущена программа.
#include Теперь научимся немного работать с командной строкой. Это понадобится для того, чтобы передавать аргументы нашей программе.
Сочетание клавиш Win+R вызывает окно "Выполнить". Наберите в нём cmd и вы откроете командную строку. Также можно найти cmd.exe поиском в меню Пуск.
В юникс-подобных операционных системах можно вызвать программу "терминал". Мы не будем изучать сколько-нибудь много команд. Только те, которые понадобятся в работе. Стандартная для всех операционных систем команда cd осуществляет переход к нужной папке. Существует два зарезервированных имени - . (точка) и.. (две точки). Точка - это имя текущей папки.
Никуда не переходит
Обращение к родительской папке
Переход в родительскую папку
Для перехода по нужному пишется cd адрес. Например, нужно перейти на windows в папку C:\Windows\System32
Cd C:\Windows\System32
В линуксе если нужно перейти в папку /var/mysql
Cd /var/mysql
Если путь содержит пробелы, то он пишется в двойных кавычках
Cd "D:\Docuents and Settings\Prolog"
Терминал имеет следующие полезные особенности: если нажать стрелку вверх, по появится предыдущая выполненная команда. Если нажать tab, то терминал
попытается дополнить строку до известной ему команды, или дополнить путь, перебирая все папки и файлы в текущей папке.
Ещё одна важная команда dir на windows и ls на linux, выводит на консоль содержимое текущей папки (той папки, в которой вы находитесь в данный момент) Ваша программа вернула своё полное имя. Перейдите в папку, где располагается ваша программа и посмотрите её содержимое Теперь, после того, как мы перешли в нашу папку, можно выполнить нашу программу. Для этого наберите её имя. Заметьте - имя изменилось. Так как программа вызывается из своей папки, то выводится относительно имя. Теперь изменим программу и сделаем так, чтобы она выводила все
аргументы. которые ей переданы.
#include Соберите проект. Перед сборкой убедитесь, что программа закрыта. Теперь вызовите программу, передав ей разные аргументы. Для этого напишите имя программы и через пробел аргументы Давайте теперь напишем программу, которая получает два аргумента числа и выводит их сумму
#include Соберём и вызовем Таким образом работает большинство программ. Кликая на ярлык, вы вызываете программу, на которую он ссылается. Большинство программ также принимают различные аргументы. Например,
можно вызвать браузер firefox из командной строки и передать аргументы
Многие стандартные команды также имеют параметры. В windows принято, что они начинаются с прямого слеша, в юниксе с минуса или двух минусов. Например
Выводит только папки, а в терминале linux
Ls -l
выводит все файлы и папки с указанием атрибутов Для просмотра дополнительных команд windows наберите в командной строке help или смотрите руководство (его легко найти в интернете). Для линукса команд и их опций гораздо больше, а некоторые из них являются самостоятельными языками программирования, так что стоит выучить хотя бы минимальный набор и их опции. Однажды заинтересовался, содержимым стека функции main процесса в linux. Провел некоторые изыскания и теперь представляю вам результат. Варианты описания функции main: Argc - число параметров Размер сегмента стека можно глянуть в файле maps: Перед тем, как загрузчик передаст управление в main, он инициализирует содержимое массивов параметров командной строки, переменных окружения, вспомогательный вектор. Для 32 битов не проверял, но скорее всего достаточно только разделить размеры на два. 1. Обращение к адресам, выше верхней точки, вызывает Segfault. Вспомогательный вектор Второй способ получить содержимое вектора: Самый удобочитаемое представление получается установкой переменной окружения LD_SHOW_AUXV. LD_SHOW_AUXV=1 ls Возвращение из main() Надеюсь, было интересно. Спасибо пользователю Xeor за полезную наводку. Бывает, что данные в программу передаются из командной строки при ее вызове. Такие данные называются аргументами командной строки. Выглядит это так, например:
./a.out test.txt
ls -lt /home/peter/
Здесь вызываются программы a.out (из текущего каталога) и ls (из одного каталога, указанного в переменной окружения PATH). Первая программа из командной строки получает одно слово - test.txt, вторая - два: -lt и /home/peter/. Если программа написана на языке C, то при ее запуске управление сразу передается в функцию main() , следовательно, именно она получает аргументы командной строки, которые присваиваются ее переменным-параметрам. До этого мы определяли функцию main() так, как-будто она не принимает никакие параметры и ничего не возвращает. На самом деле в языке C любая функция по-умолчанию (если не определено ничего иного) возвращает целое число. В этом можно убедиться. Если записать код таким образом: main()
{
printf
("Hi\n
"
)
;
return
0
;
}
То никакого предупреждения или ошибки при компиляции не возникнет. То же самое будет, если записать int main() . Это доказывает, что функция по-умолчанию возвращает целое число, а не ничто (void). Хотя то, что возвращает функция всегда можно "переопределить", например, voidmain() или float main() . При вызове программы из командной строки в нее всегда передается пара данных: Следует иметь в виду, что само имя программы также считается. Например, если вызов выглядит так:
./a.out 12 theme 2
То первый аргумент программы имеет значение 4, а массив строк определяется как {"./a.out", "12", "theme", "2"}. Обратите внимание на терминологию, есть всего два аргумента программы (число и массив), но сколько угодно аргументов командной строки. Аргументы командной строки "преобразуются" в аргументы программы (в аргументы функции main()). То, что в программу передаются данные, вовсе не означает, что функция main() должна их принимать. Если функция main() определена без параметров, то получить доступ к аргументам командной строки невозможно. Хотя ничего вам не мешает их передавать. Ошибки не возникнет. Чтобы получить доступ к переданным в программу данным, их необходимо присвоить переменным. Поскольку аргументы сразу передаются в main() , то ее заголовок должен выглядеть таким образом: В первой переменной (n) содержится количество слов, а во второй - указатель на массив строк. Часто второй параметр записывают в виде **arr . Однако это то же самое. Вспомним, что сам массив строк, содержит в качестве своих элементов указатели на строки. А в функцию мы передаем указатель на первый элемент массива. Получается, что передаем указатель на указатель, т.е. **arr . Задание
#include Она выводит количество слов в командной строке при ее вызове и каждое слово с новой строки. Вызовите ее без аргументов командной строки и с аргументами. В программе мы использовали переменные-параметры argc и argv. Принято использовать именно такие имена, но на самом деле они могут быть любыми. Лучше придерживаться этого стандарта, чтобы ваши программы были более понятны не только вам, но и другим программистам. Если у вас есть опыт работы в командной строке GNU/Linux, вы знаете, что у большинства команд есть ключи и аргументы. Например, при просмотре содержимого каталогов, копировании, перемещении в качестве аргументов указываются объекты файловой системы, над которыми выполняется команда. Особенности ее выполнения определяются с помощью ключей. Например, в команде Cp -r ../les_1 ../les_101
cp - это имя команды, -r - ключ, а../les_1 и../les_101 - аргументы команды. Вообще чаще всего в программы при их запуске передаются адреса файлов и "модификаторы" (это ключи) процесса выполнения программы. Напишем программу, которая открывает указанные пользователем в командной строке файлы на запись или добавление и записывает (добавляет) туда одну и туже информацию, которую пользователь вводит с клавиатуры в процессе выполнения программы: #include Пояснения к коду:Параметры командной строки
Наберите cd C:\
нажимайте tab и смотрите, что происходит.
firefox.exe "www.mozilla.org" "сайт" и он сразу же откроет в двух вкладках сайты по указанным адресам.
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)
argv - нуль-терминальный массив указателей на строки параметров командной строки
env - нуль-терминальный массив указателей на строки переменных окружения. Каждая строка в формате ИМЯ=ЗНАЧЕНИЕ
auxv - массив вспомогательных значение (доступно только для PowerPC )
apple - путь к исполняемому файлу (в MacOS и Darwin )
Вспомогательный вектор - массив с различной дополнительной информацией, такой как эффективный идентификатор пользователя, признак setuid бита, размер страницы памяти и т.п.
cat /proc/10918/maps
…
7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0
…
После инициализации верхняя часть стека выглядит примерно так, для 64битной версии.
Старший адрес сверху.1.
0x7ffffffff000
Верхняя точка сегмента стека. Обращение вызывает segfault
0x7ffffffff0f8
NULL
void*
8
0x00"
2.
filename
char
1+
«/tmp/a.out»
char
1
0x00
...
env
char
1
0x00
...
char
1
0x00
3.
0x7fffffffe5e0
env
char
1
..
char
1
0x00
...
argv
char
1
0x00
...
char
1
0x00
4.
0x7fffffffe5be
argv
char
1+
«/tmp/a.out»
5.
Массив случайной длины
6.
данные для auxv
void*
48"
AT_NULL
Elf64_auxv_t
16
{0,0}
...
auxv
Elf64_auxv_t
16
7.
auxv
Elf64_auxv_t
16
Ex.: {0x0e,0x3e8}
NULL
void*
8
0x00
...
env
char*
8
8.
0x7fffffffe308
env
char*
8
0x7fffffffe5e0
NULL
void*
8
0x00
...
argv
char*
8
9.
0x7fffffffe2f8
argv
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.
Переменные локальных функций
" - описания полей в документах не нашел, но в дампе явно видны.
2. Строка, содержащая путь к исполняемому файлу.
3. Массив строк с переменными окружения
4. Массив строк с параметрами командной строки
5. Массив случайной длинны. Его выделение можно отключить командами
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. Данные для вспомогательного вектора (например строка «x86_64»)
7. Вспомогательный вектор. Подробнее ниже.
8. Нуль-терминальный массив указателей на строки переменных окружения
9. Нуль-терминальный массив указателей на строки параметров командной строки
10.Машинное слово, содержащее число параметров командной строки (один из аргументов «старших» функций см. п. 11)
11.Локальные переменные и аргументы, функций вызываемых до main(_start,__libc_start_main..)
12.Переменные, объявленные в main
13.Аргументы функции main
14.Переменные и аргументы локальных функций.
Для i386 и x86_64 нельзя получить адрес первого элемента вспомогательного вектора, однако содержимое этого вектора можно получить другими способами. Один из них - обратиться к области памяти, лежащей сразу за массивом указателей на строки переменных окружения.
Это должно выглядеть примерно так:
#include
Структуры Elf{32,64}_auxv_t описаны в /usr/include/elf.h. Функции заполнения структур в linux-kernel/fs/binfmt_elf.c
hexdump /proc/self/auxv
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(), а в функцию _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.
Вот что получилось(работоспособность зависит от версии компилятора):
#include
Удач.
Эти данные (число и указатель) передаются в программу даже тогда, когда она просто вызывается по имени без передачи в нее чего-либо: ./a.out. В таком случае первый аргумент имеет значение 1, а второй указывает на массив, состоящий всего из одной строки {"./a.out"}.
main (int n, char *arr)
Напишите такую программу:Практическое значение передачи данных в программу