При создании консольного приложения в языке программирования С++, автоматически создается строка очень похожая на эту:
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 , но это все зависит от типа создаваемого приложения или от среды разработки. Необязательные и именованные аргументы В версии C# 4.0 внедрено новое средство, повышающее удобство указания аргументов при вызове метода. Это средство называется необязательными аргументами
и
позволяет определить используемое по умолчанию значение для параметра метода. Данное значение будет использоваться по умолчанию в том случае, если для параметра не указан соответствующий аргумент при вызове метода. Следовательно, указывать
аргумент для такого параметра не обязательно. Необязательные аргументы позволяют
упростить вызов методов, где к некоторым параметрам применяются аргументы, выбираемые по умолчанию. Их можно также использовать в качестве "сокращенной"
формы перегрузки методов . Главным стимулом для добавления необязательных
аргументов послужила необходимость в упрощении взаимодействия с объектами СОМ. В нескольких объектных моделях Microsoft (например, Microsoft Office) функциональность предоставляется через объекты СОМ, многие из которых были написаны давно и рассчитаны на использование необязательных параметров. Пример использования необязательных аргументов показан ниже: Using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
// Аргументы b и с указывать при вызове необязательно
static int mySum(int a, int b = 5, int c = 10)
{
return a + b + c;
}
static void Main()
{
int sum1 = mySum(3);
int sum2 = mySum(3,12);
Console.WriteLine("Sum1 = "+sum1);
Console.WriteLine("Sum2 = "+sum2);
Console.ReadLine();
}
}
} Следует иметь в виду, что все необязательные аргументы должны непременно указываться справа от обязательных. Помимо методов, необязательные аргументы можно применять в конструкторах, индексаторах и делегатах. Преимущество необязательных аргументов заключается, в частности, в том, что
они упрощают программирующему обращение со сложными вызовами методов и конструкторов. Ведь нередко в методе приходится задавать больше параметров, чем
обычно требуется. И в подобных случаях некоторые из этих параметров могут быть
сделаны необязательными благодаря аккуратному применению необязательных аргументов. Это означает, что передавать нужно лишь те аргументы, которые важны в
данном конкретном случае, а не все аргументы, которые в противном случае должны быть обязательными. Такой подход позволяет рационализировать метод и упростить
программирующему обращение с ним. Еще одной функциональной возможностью, которая добавилась в C# с выходом версии.NET 4.0, является поддержка так называемых именованных аргументов (named
arguments)
. Как известно, при передаче аргументов методу порядок их следования,
как правило, должен совпадать с тем порядком, в котором параметры определены в самом методе. Иными словами, значение аргумента присваивается параметру по его
позиции в списке аргументов. Данное ограничение призваны преодолеть именованные аргументы. Именованный аргумент позволяет указать имя того параметра, которому
присваивается его значение. И в этом случае порядок следования аргументов уже не имеет никакого значения. Таким образом, именованные аргументы в какой-то степени
похожи на упоминавшиеся ранее инициализаторы объектов, хотя и отличаются от
них своим синтаксисом.
Для указания аргумента по имени служит следующая форма синтаксиса: имя_параметра: значение
Здесь имя_параметра
обозначает имя того параметра, которому передается значение. Разумеется, имя_параметра должно обозначать имя действительного параметра для вызываемого метода. Обратите внимание, в этой версии main() никаких параметров нет. Тем не менее, многие программы нуждаются в некоторых входных данных. Например, предположим, что вы пишете программу под названием Picture, которая принимает изображение в качестве входных данных, а затем делает из этого изображения миниатюру (уменьшенная версия изображения). Как функция Picture узнает, какое изображение нужно принять и обработать? Пользователь должен сообщить программе, какой файл следует открыть. Это можно сделать следующим образом: // Программа: Picture
#include Тем не менее, здесь есть потенциальная проблема. Каждый раз, при запуске, программа будет ожидать пользовательский ввод. Это не проблема, если вы вручную запускаете программу из командной строки один раз для одного изображения. Но это уже проблема, если вы хотите работать с большим количеством файлов или чтобы другая программа имела возможность запустить эту программу. Рассмотрим это детальнее. Например, вы хотите создать миниатюры для всех файлов-изображений, которые находятся в определённом каталоге. Как это сделать? Вы можете запускать эту программу столько раз, сколько есть изображений в каталоге, введя каждое имя файла вручную. Однако, если есть сотни изображений, такой подход будет, мягко говоря, не очень эффективен! Решением здесь будет написать программу, которая перебирала бы каждое имя файла в каталоге, вызывая каждый раз Picture для каждого файла. Теперь рассмотрим случай, когда у вас есть веб-сайт, и вы хотите, чтобы он создавал миниатюру каждый раз, когда пользователь загружает изображение на сайт. Эта программа не может принимать входные данные из Интернета и следует логический вопрос: «Как тогда вводить имя файла?». Выход есть: вызов веб-сервером функции Picture автоматически каждый раз после загрузки файла. В обоих случаях нам нужно, чтобы внешняя программа передавала имя файла в качестве входных данных в нашу программу при её запуске, вместо того, чтобы Picture сам дожидался, пока пользователь вручную введёт имя файла. Аргументы командной строки
— это необязательные строковые аргументы, передаваемые операционной системой в программу при её запуске. Программа может их использовать в качестве входных данных, либо игнорировать. Подобно тому, как параметры одной функции предоставляют данные для параметров другой функции, так и аргументы командной строки предоставляют возможность людям или программам предоставлять входные данные для программы. Исполняемые программы могут запускаться в командной строке через вызов. Например, для запуска исполняемого файла MyProgram, который находится в корневом каталоге диска C в ОС Windows вам нужно ввести: C:\>MyProgram Чтобы передать аргументы командной строки в MyProgram, вам нужно будет их просто перечислить после имени исполняемого файла: C:\>MyProgram SomeContent.txt Теперь, при запуске MyProgram, SomeContent.txt будет предоставлен в качестве аргумента командной строки. Программа может иметь несколько аргументов командной строки, разделённых пробелами: C:\>MyProgram SomeContent.txt SomeOtherContent.txt Это также работает и с другими операционными системами, например, с Linux (хотя структура каталогов будет отличаться от структуры каталогов в Windows). Если вы запускаете свою программу из среды IDE, то ваша IDE должна предоставить способ ввода аргументов командной строки. Для пользователей Visual Studio
: Щёлкните правой кнопкой мыши на нужный проект в Обозревателе Решений, а затем выберите «Свойства»
: Затем «Свойства конфигурации > Отладка»
. На правой панели будет строка «Аргументы команды»
. Вы сможете здесь ввести аргументы командной строки, и они будут автоматически переданы вашей программе при её запуске: Пользователям Code::Blocks
нужно выбрать «Project > Set program`s arguments»:
Теперь, когда вы знаете, как передавать аргументы командной строки в программу, следующим шагом будет доступ к ним из программы. Для этого используется уже другая форма функции main(), которая принимает два аргумента (argc и argv) следующим образом: int main(int argc, char *argv) Также вы можете увидеть и такой вариант: int main(int argc, char** argv) int
main
(int
argc
,
char
*
*
argv
)
Хоть оба эти варианта идентичны по своей сути, но рекомендуется использовать первый, так как он интуитивно понятнее. argc (англ. «arg
ument c
ount» = «количество аргументов») — это целочисленный параметр, содержащий количество аргументов, переданных в программу. argc всегда будет как минимум 1, так как первым аргументом всегда является имя самой программы. Каждый аргумент командной строки, который предоставляет пользователь, заставит argc увеличиться на 1. argv (англ. «arg
ument v
alues» = «значения аргументов») — это место, где хранятся фактические значения аргументов. Хотя объявление argv выглядит немного пугающе, но это всего лишь массив . Длина этого массива — argc . Давайте напишем короткую программу MyArguments, которая будет выводить значения всех аргументов командной строки: // Программа: MyArguments
#include // Программа: MyArguments
#include int
main
(int
argc
,
char
*
argv
)
// Перебираем каждый аргумент и выводим его порядковый номер и значение
for
(int
count
=
0
;
count
<
argc
;
++
count
)
std
::
cout
<<
count
<<
" "
<<
argv
[
count
]
<<
"\n"
;
return
0
;
Теперь, при вызове MyArguments с аргументами командной строки SomeContent.txt и 200 , вывод будет следующим: There are 3 arguments: Параметр 0 — это путь и имя текущей программы. Параметры 1 и 2 здесь являются аргументами командной строки, которые мы передали. Аргументы командной строки всегда передаются в качестве строк, даже если предоставленное значение является числовым. Чтобы использовать аргумент командной строки в виде числа, вам нужно будет конвертировать его из строки в число. К сожалению, в C++ это делается немного сложнее, чем оно должно быть: #include #include #include #include #include int
main
(int
argc
,
char
*
argv
)
if
(argc
<=
1
)
// В некоторых операционных системах, argv может быть просто пустой строкой, без имени программы
// Обрабатываем случай, когда argv может быть пустым или не пустым
if
(argv
[
0
]
)
std
::
cout
<<
"Usage: "
<<
argv
[
0
]
<<
" else
std
::
cout
<<
"Usage: exit
(1
)
;
При автоматизированном создании консольного приложения в языке программирования С++, автоматически создается главная функция очень похожая на эту: int
main(int
argc, char
* argv) Заголовок функции содержит сигнатуру главной функции main()
с аргументами argс
и argv
. При запуске программы через командную строку Windows можно передавать ей некоторую информацию. При этом командная строка будет иметь вид: Аргументы командной строки разделяются одним или несколькими пробелами. Аргумент argv
содержит полное имя приложения: #include
cout << argv << endl; Return
0; Результат выполнения Пример
: вычисление произведения двух целых чисел #include
Int
a = 0, b=0; If
(argc > 1) a = StrToInt(argv); If
(argc > 2) b = StrToInt(argv); cout << a <<«*»
<< b << «= «
<< a*b << endl; Return
0; Запуск программы осуществляется как Результат выполнения Для передачи аргументов командной строки при отладке программы необходимо обратиться к меню Свойства
проекта. При запуске программы в режиме отладки введенные аргументы будут восприниматься программой как аргументы командной строки.
Однажды заинтересовался, содержимым стека функции main процесса в linux. Провел некоторые изыскания и теперь представляю вам результат. Варианты описания функции main: Argc - число параметров Размер сегмента стека можно глянуть в файле maps: Перед тем, как загрузчик передаст управление в main, он инициализирует содержимое массивов параметров командной строки, переменных окружения, вспомогательный вектор. Для 32 битов не проверял, но скорее всего достаточно только разделить размеры на два. 1. Обращение к адресам, выше верхней точки, вызывает Segfault. Вспомогательный вектор Второй способ получить содержимое вектора: Самый удобочитаемое представление получается установкой переменной окружения LD_SHOW_AUXV. LD_SHOW_AUXV=1 ls Возвращение из main() Надеюсь, было интересно. Спасибо пользователю Xeor за полезную наводку.Необязательные аргументы
Именованные аргументы
Передача аргументов командной строки
Использование аргументов командной строки
0 C:\MyArguments
1 SomeContent.txt
2 200Обработка числовых аргументов
{…}
Если программу запускать через командную строку, то существует возможность передать какую-либо информацию этой программе. Для этого существуют аргументы командной строки argc
и argv
.
Параметр argc
имеет тип int
, и содержит количество параметров, передаваемых в функцию main
. Причем argc
всегда не меньше 1, даже когда функции main
не передается никакой информации, так как первым параметром считается имя приложения.
Параметр argv
представляет собой массив указателей на строки. Через командную строку можно передать только данные строкового типа.
Диск:\путь\имя.exe аргумент1 аргумент2 …
using namespace
std;
}
В программе используется функция преобразования строки в целое число StrToInt()
отсюда .
using namespace
std;
int
StrToInt(char
*s) {…}
int
main(int
argc, char
* argv) {
}Отладка программы с аргументами командной строки
На вкладке Свойства конфигурации ->Отладка
выбрать Аргументы команды
и задать их значения.
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
Удач.