11.11 – Аргументы командной строки
Необходимость аргументов командной строки
Как вы узнали из урока «0.4 – Введение в разработку на C++», при компиляции и компоновке программы на выходе получается исполняемый файл. Когда программа запускается, выполнение начинается с функции main()
. До этого момента мы объявляли main
следующим образом:
int main()
Обратите внимание, что эта версия main()
не принимает параметров. Однако для работы со многими программами требуются какие-то входные данные. Например, предположим, что вы пишете программу под названием Thumbnail, которая считывает файл изображения, а затем создает миниатюру (уменьшенную версию этого изображения). Как Thumbnail узнает, какое изображение прочитать и обработать? Пользователь должен каким-то образом указать программе, какой файл открыть. Для этого вы можете использовать следующий подход:
// Программа: Thumbnail
#include <iostream>
#include <string>
int main()
{
std::cout << "Please enter an image filename to create a thumbnail for: ";
std::string filename{};
std::cin >> filename;
// открываем файл изображения
// создаем миниатюру
// выводим миниатюру
}
Однако при таком подходе есть потенциальная проблема. Каждый раз, когда программа запускается, она будет ждать, пока пользователь введет данные. Это может не быть проблемой, если вы запускаете эту программу один раз вручную из командной строки. Но это проблематично в других случаях, например, когда вы хотите запустить эту программу для многих файлов или запустить ее другой программой.
Давайте рассмотрим эти случаи подробнее.
Рассмотрим случай, когда вы хотите создать миниатюры для всех файлов изображений в заданном каталоге. Как бы вы это сделали? Вы можете запускать эту программу столько раз, сколько изображений в каталоге, печатая имя каждого файла вручную. Однако если бы изображений были сотни, это могло бы занять целый день! Хорошим решением здесь было бы написать программу, которая перебирает имя каждого файла в каталоге, вызывая Thumbnail один раз для каждого файла.
Теперь рассмотрим случай, когда вы запускаете веб-сайт и хотите, чтобы на вашем сайте создавался эскиз каждый раз, когда пользователь загружает изображение на ваш сайт. Эта программа не настроена для приема входных данных из Интернета, так как же человек, загружающий файл, будет вводить имя файла в этом случае? Хорошим решением здесь было бы, чтобы ваш веб-сервер автоматически вызывал Thumbnail после загрузки.
В обоих этих случаях нам нужен способ, чтобы внешняя программа могла передавать имя файла в качестве входных данных для нашей программы Thumbnail
при ее запуске, а не заставлять Thumbnail ждать после запуска, пока пользователь введет имя файла.
Аргументы командной строки – это необязательные строковые аргументы, которые операционная система передает программе при ее запуске. Затем программа может использовать их в качестве входных данных (или игнорировать). Подобно параметрам функции, которые позволяют функции предоставлять входные данные для другой функции, аргументы командной строки позволяют людям или программам предоставлять входные данные программе.
Передача аргументов командной строки
Исполняемые программы можно запускать из командной строки, вызывая их по имени. Например, чтобы запустить исполняемый файл "WordCount", который находится в корневом каталоге диска C: на компьютере с Windows, вы можете ввести:
C:\>WordCount
Чтобы передать аргументы командной строки в WordCount, мы просто перечисляем их после имени исполняемого файла:
C:\>WordCount Myfile.txt
Теперь при выполнении WordCount Myfile.txt будет предоставлен в качестве аргумента командной строки. Программа может иметь несколько аргументов командной строки, разделенных пробелами:
C:\>WordCount Myfile.txt Myotherfile.txt
Это также работает и в других операционных системах командной строки, таких как Linux (хотя приглашение и структура каталогов, несомненно, будут отличаться).
Если вы запускаете свою программу из среды IDE, в среде IDE должен быть предусмотрен способ ввода аргументов командной строки.
В Microsoft Visual Studio кликните правой кнопкой мыши на своем проекте в обозревателе решений и выберите «Свойства» (Properties). В открывшемся окне разверните дерево «Свойства конфигурации» (Configuration Properties) и выберите «Отладка» (Debugging). На правой панели есть строка с названием «Аргументы команды» (Command Arguments). Вы можете ввести туда аргументы командной строки для тестирования, и они будут автоматически переданы вашей программе при ее запуске.
В Code::Blocks выберите «Project» (Проект) → «Set program’s arguments» (Установить аргументы программы).
Использование аргументов командной строки
Теперь, когда вы знаете, как предоставить программе аргументы командной строки, следующим шагом будет доступ к ним из нашей программы на C++. Для этого мы используем другую форму main()
. Эта новая форма main()
принимает два аргумента (по соглашению названные argc
и argv
) следующим образом:
int main(int argc, char *argv[])
Иногда вы также можете увидеть и такое:
int main(int argc, char** argv)
Несмотря на то, что они обрабатываются одинаково, мы предпочитаем первое представление, потому что его интуитивно легче понять.
argc
– это целочисленный параметр, содержащий счетчик числа аргументов, переданных программе (argc
= argument count, число аргументов). argc
всегда будет не меньше 1 потому, что первым аргументом всегда является имя самой программы. Каждый аргумент командной строки, предоставляемый пользователем, приведет к увеличению argc
на 1.
argv
– это место, где хранятся фактические значения аргументов (argv
= argument values, значения аргументов, хотя на самом деле расшифровывается как «argument vectors»). Хотя объявление argv
выглядит устрашающе, на самом деле argv
представляет собой просто массив строк в стиле C. Длина этого массива – argc
.
Давайте напишем короткую программу с именем MyArgs для вывода значений всех параметров командной строки:
// Программа: MyArgs
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "There are " << argc << " arguments:\n";
// Перебираем все аргументы и
// выводим номер и значение каждого из них
for (int count{ 0 }; count < argc; ++count)
{
std::cout << count << ' ' << argv[count] << '\n';
}
return 0;
}
Теперь, когда мы вызываем эту программу (MyArgs) с аргументами командной строки "Myfile.txt" и "100", вывод будет следующим:
There are 3 arguments:
0 C:\MyArgs
1 Myfile.txt
2 100
Аргумент 0 – это путь и имя текущей запущенной программы. Аргументы 1 и 2 в данном случае – это два параметра командной строки, которые мы передали.
Работа с числовыми аргументами
Аргументы командной строки всегда передаются в виде строк, даже если предоставленное значение является числовым. Чтобы использовать аргумент командной строки в качестве числа, вы должны преобразовать его из строки в число. К сожалению, C++ делает это немного сложнее, чем должно быть.
В C++ это можно сделать следующим образом:
#include <iostream>
#include <sstream> // для std::stringstream
#include <string>
int main(int argc, char *argv[])
{
if (argc <= 1)
{
// В некоторых операционных системах argv[0] может оказаться пустой
// строкой вместо имени программы.
// Мы добавим зависимость для нашего ответа от того,
// является ли argv[0] пустым или нет.
if (argv[0])
std::cout << "Usage: " << argv[0] << " <number>" << '\n';
else
std::cout << "Usage: <program name> <number>" << '\n';
return 1;
}
// устанавливаем переменную строкового потока с именем convert,
// инициализированную входными данными из argv[1]
std::stringstream convert{ argv[1] };
int myint{};
if (!(convert >> myint)) // выполняем преобразование
myint = 0; // если преобразование не удалось,
//установим для myint значение по умолчанию
std::cout << "Got integer: " << myint << '\n';
return 0;
}
При запуске с вводом "567" эта программа печатает:
Got integer: 567
std::stringstream
работает так же, как std::cin
. В этом случае мы инициализируем его значением argv[1]
, и поэтому можем использовать operator>>
для извлечения значения в целочисленную переменную (так же, как и с std::cin
).
Подробнее о std::stringstream
мы поговорим в следующей главе.
Операционная система анализирует аргументы командной строки первой
Когда вы вводите что-то в командной строке (или запускаете свою программу из IDE), операционная система должна преобразовать и направить этот запрос соответствующим образом. Это не только включает в себя запуск исполняемого файла, но также включает анализ любых аргументов, чтобы определить, как они должны обрабатываться и передаваться приложению.
Как правило, в операционных системах действуют особые правила обработки специальных символов, таких как двойные кавычки и обратный слеш.
Например:
MyArgs Hello world!
печатает:
There are 3 arguments:
0 C:\MyArgs
1 Hello
2 world!
Обычно строки, переданные в двойных кавычках, считаются частью одной строки:
MyArgs "Hello world!"
печатает:
There are 2 arguments:
0 C:\MyArgs
1 Hello world!
Если вы хотите включить двойную кавычку в состав строки, вам нужно поставить перед двойной кавычкой обратный слеш:
MyArgs \"Hello world!\"
печатает:
There are 3 arguments:
0 C:\MyArgs
1 "Hello
2 world!"
Заключение
Аргументы командной строки предоставляют пользователям и другим программам отличный способ передать входные данные в программу при запуске. Рассмотрите возможность использования любых входных данных, необходимых для работы программы при запуске, в качестве параметров командной строки. Если они не будут переданы через командную строку, вы всегда можете обнаружить это и попросить пользователя ввести данные. Таким образом, ваша программа сможет работать в любом случае.