Урок №110. Аргументы командной строки

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 88116

 ǀ   16 

На этом уроке мы рассмотрим, что такое аргументы командной строки в языке C++ и то, как они используются.

Аргументы командной строки

Из урока №3 мы уже знаем, что при компиляции и линкинге, компилятор создает исполняемый файл. Когда программа запускается, выполнение начинается с первой строки функции main(). До этого урока мы объявляли main() следующим образом:

Обратите внимание, в этой версии функции main() никаких параметров нет. Тем не менее, многие программы нуждаются в некоторых входных данных. Например, предположим, что вы пишете программу под названием Picture, которая принимает изображение в качестве входных данных, а затем делает из этого изображения миниатюру (уменьшенная версия изображения). Как функция picture() узнает, какое изображение нужно принять и обработать? Пользователь должен сообщить программе, какой файл следует открыть. Это можно сделать следующим образом:

Тем не менее, здесь есть потенциальная проблема. Каждый раз при запуске программа будет ожидать пользовательский ввод. Это не проблема, если вы вручную запускаете программу из командной строки один раз для одного изображения. Но это уже проблема, если вы хотите работать с большим количеством файлов или чтобы другая программа имела возможность запустить эту программу.

Рассмотрим это детально. Например, вы хотите создать миниатюры для всех файлов-изображений, которые находятся в определенном каталоге. Как это сделать? Вы можете запускать эту программу столько раз, сколько есть изображений в каталоге, введя каждое имя файла вручную. Однако, если есть сотни изображений, такой подход будет, мягко говоря, не очень эффективным! Решением здесь будет написать программу, которая перебирала бы каждое имя файла в каталоге, вызывая каждый раз функцию 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) следующим образом:

Также вы можете увидеть и такой вариант:

Хоть оба эти варианта идентичны по своей сути, но рекомендуется использовать первый, так как он интуитивно понятнее.

argc (англ. «argument count» = «количество аргументов») — это целочисленный параметр, содержащий количество аргументов, переданных в программу. argc всегда будет как минимум один, так как первым аргументом всегда является имя самой программы. Каждый аргумент командной строки, который предоставляет пользователь, заставит argc увеличиться на единицу.

argv (англ. «argument values» = «значения аргументов») — это место, где хранятся фактические значения аргументов. Хотя объявление argv выглядит немного пугающе, но это всего лишь массив строк C-style. Длиной этого массива является argc.

Давайте напишем короткую программу MyArguments, которая будет выводить значения всех аргументов командной строки:

Теперь, при вызове MyArguments с аргументами командной строки SomeContent.txt и 200, вывод будет следующим:

There are 3 arguments:
0 C:\MyArguments
1 SomeContent.txt
2 200

Нулевой параметр — это путь и имя текущей программы. Первый и второй параметры здесь являются аргументами командной строки, которые мы передали.

Обработка числовых аргументов


Аргументы командной строки всегда передаются в качестве строк, даже если предоставленное значение является числовым. Чтобы использовать аргумент командной строки в виде числа, вам нужно будет конвертировать его из строки в число. К сожалению, в языке C++ это делается немного сложнее, чем должно быть:

Если мы запустим эту программу с аргументом командной строки 843, то результатом будет:

Got integer: 843

std::stringstream работает почти так же, как и std::cin. Здесь мы инициализируем переменную std::stringstream значением argv[1], так что мы можем использовать оператор >> для извлечения значения в переменную типа int.

Анализ аргументов командной строки

Когда вы пишете что-то в командной строке (или запускаете свою программу из среды IDE), то операционная система ответственна за то, чтобы ваш запрос проделал правильный путь. Это связано не только с запуском исполняемого файла, но и с анализом любых аргументов для определения того, как их следует обрабатывать и передавать в программу.

Операционные системы имеют обязательные правила обработки специальных символов (двойные кавычки, бэкслешы и т.д.).

Например:

MyArguments Hello world!

Результат:

There are 3 arguments:
0 C:\MyArguments
1 Hello
2 world!

Строки, переданные в двойных кавычках, считаются частью одной и той же строки:

MyArguments "Hello world!"

Результат:

There are 2 arguments:
0 C:\MyArguments
1 Hello world!

Для того, чтобы вывести каждое слово на отдельной строке, используйте бэкслешы:

MyArguments \"Hello world!\"

Результат:

There are 3 arguments:
0 C:\MyArguments
1 "Hello
2 world!"

Заключение


Аргументы командной строки предоставляют отличный способ для пользователей или других программ передавать входные данные в программу при её запуске. Используйте любые входные данные, необходимые программе при запуске, в качестве аргументов командной строки. Если командная строка не передана, то вы всегда сможете это обнаружить и попросить пользователя ввести данные вручную. Таким образом, ваша программа будет работать в любом случае.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (279 оценок, среднее: 4,81 из 5)
Загрузка...

Комментариев: 16

  1. Олександр:

    Рассмотрим это детально. Например, вы хотите создать миниатюры для всех файлов-изображений, которые находятся в определенном каталоге. Как это сделать? Вы можете запускать эту программу столько раз, сколько есть изображений в каталоге, введя каждое имя файла вручную. Однако, если есть сотни изображений, такой подход будет, мягко говоря, не очень эффективным! Решением здесь будет написать программу, которая перебирала бы каждое имя файла в каталоге, вызывая каждый раз функцию picture() для каждого файла.

    То есть в программу можно отправить каталог/папку и с помощью каких то функций С++ перебрать все файлы. Я правильно понял? Если да, то что это за функции?

  2. Дмитрий:

    Почему в примере int main(int argc, char *argv[]) char *argv[] назван как массив строк C-style? Разве это не массив указателей?

  3. Finchi:

    Не проще ли использовать std::stoi(argv[1]) для конвертации строки в integer?

  4. Константин:

    Юра, пожалуйста, подскажи почему запуская

    у меня в Code::Blocks 20.03 выводится только
    0 путь к бинарному файлу.ехе
    1 директория
    2 имя файла.txt (из которого я собираюсь заносить данные в int main(int argc, char *argv[])),
    а сами данные не извлекаются?

  5. Дима:

    Обработка аргументов командной строки — это то, с чего вообще надо было начинать рассказ о получении данных от пользователя. На практике подавляющее большинство программ получает пользовательский ввод именно через командную строку а не через стандартный ввод. Функцию main лучше сделать такой

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

  6. Дмитрий:

    огромное спасибо за статью! никто кроме вас не смог понятно изложить

  7. hillbilly:

    Как понимать фразу:
    "В некоторых операционных системах, argv[0] может быть просто пустой строкой, без имени программы"
    То есть вы хотите сказать что некоторые операционные системы инициализируют указатель argv[0] в nullptr???
    Если это так то все понятно, если нет то объясните логику условия:
    if (argv[0])

    1. Steindvart:

      Пустая строка не есть nullprt. Указатель на что-то, если он не nullptr (или NULL) преобразуется в true, даже если это указатель на пустую строку "". То есть, которая состоит только из нуль-символа.

      Поэтому тут всё корректно.

  8. Woland:

    Может кому пригодится такой момент, если кто-то собирается писать в универсальном стиле (мультибайт/юникод). Сразу скажу, что в параметрах main тип wchar_t не работает. Так как argv[i] всегда будет возвращать 0.

    Поэтому непонятно, что делать если вы работаете с UTF (L"Text"), а в параметрах main всегда char.
    (Кому пока непонятно — не беда. В конце ссылка на то, что пригодится позже.)

    Пример проверки существования файла переданного как аргумент (суть в преобразовании std::string в std::wstring):

    Работает с версией C++ 17 и выше.
    Если кто-то знает как лучше преобразовать std::string в std::wstring, напишите.

    В дополнение ссылка на хорошее пояснение про мультибайт/юникод — https://habr.com/ru/post/164193/

    Оставляете по мере изучения и практики полезные примеры в поддержку автора перевода 😉
    Всем терпения и удачи в изучении! Автору спасибо за перевод! Я добил этот курс.

  9. TurboOSMaker:

    У меня возникла такая проблема: вы привели примеры добавления аргументов для Visual Studio и Code::Blocks. А что делать пользователям Dev-C++?

    1. Илья:

      Запускать программу из командной строки, и передавать аргументы через неё

    2. Артём:

      Выполнить -> Параметры…

  10. Ксения:

    Добрый день!
    Не понятно, что именно происходит при обработке ситуации, когда argv[0] является просто пустой строкой. <program name>, <number> — они как-то инициализируются? Что именно выведет программа в случае не пустой и пустой строки?

    1. Александр:

      первым аргументом ВСЕГДА идет исполняемый файл программы. Поэтому такого просто не может произойти

    2. Andrey:

      Абсолютли ничем , это можно проверить, банально поменять if<argc >=1>, либо через отладчик посмотреть инициализацию.Отладчик и тестировние наше все 🙂

  11. Elena:

    спасибо за отличное объяснение, понятное даже новичку. помогло разобраться с 1м домашним заданием в институте. Только вот запустить из командной строки пока не получается никак..

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *