Доработать программу из подсказки, чтобы она выводила возраст юзера по году переданному через именованный параметр
Создаем проект
Попробуем чего-нибудь написать на C++, создадим папку
mkdir cpp01
cd $_
создадим простой файлик на C++, какой-нибудь hello-world вот так
nano hello.cpp
и загоним туда такой код:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World" << endl;
return 0;
}
попробуем его скомпилировать
g++ hello.cpp -o hello
в папке появится зеленый файлик hello
попробуем его запустить
./hello
и увидим
Красота =)
Обрабатываем аргумент командной строки
Попробуем теперь поработать с командной строкой, чтобы можно было передать какой-нибудь параметр программе, и она на него среагировала.
Начнём с простого. Пусть наша программа здоровается с пользователем, а само имя пользователя будем передавать в качестве параметра
./hello "Вася"
очевидно, что если сейчас запустить программу, то никакого «привета» мы не увидим:
Надо как-то получить доступ к параметрам. Как известно лежат они в аргументах функции main Перепишем код следующим образом
#include <iostream>
using namespace std;
// argc – количество параметров, argv – значения параметров
int main(int argc, char* argv[])
{
cout << argv[0] << endl; // вывести первый аргумент командной строки
return 0;
}
перекомпилируем
g++ hello.cpp -o hello
и запускаем
хм, почему-то не вывел Васю
…
дело в том что первый аргумент командной строки это всегда название программы, которую мы запустили.
Мы запускали ./hello
вот он его и написал.
Окей, давайте тогда выведем второй параметр
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
cout << argv[0] << endl;
cout << argv[1] << endl;
return 0;
}
проверим:
от теперь другое дело =)
Теперь попробуем сделать чтобы выводилось приветствие
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Привет, " << argv[1] << endl;
return 0;
}
проверяем
красота! =)
Работаем с числовым параметром
Добавим еще чтобы он мог рассчитать возраст Васи, то есть мы будем передавать ему год рождения в качестве параметра, а он нам будет считать.
Напишем пока просто такой код, чтобы год выводил
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Привет, "
<< argv[1] << endl
<< "ты родился в " << argv[2] << " году" << endl;
return 0;
}
проверим
отлично!)
Теперь, попробуем посчитать. Для этого надо преобразовать строку в число. Воспользуемся функцией atoi
Получится такой код:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int year = atoi(argv[2]); // преобразую в число
cout << "Привет, "
<< argv[1] << endl
<< "ты родился в " << year << " году" << endl; // тут теперь переменную year подставил
return 0;
}
работать должно так же:
теперь вытащим текущий год, к сожалению, в C++
это не очень веселая процедура но уж какая есть
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int year = atoi(argv[2]);
// берем текущее год
auto t = time(nullptr);
auto lt = localtime(&t);
int currentYear = lt->tm_year + 1900;
// считаем возраст
int age = currentYear - year;
cout << currentYear << endl;
// добавили вывод возраста
cout << "Привет, "
<< argv[1] << endl
<< "ты родился в " << year << " году" << endl
<< "тебе " << age << " лет" << endl;
return 0;
}
тестируем
а что будет если поменять параметры местами?
что удивительно, он сработал, но как мы видим он проинтерпретировал имя Вася как возраст, сконвертил его в 0, и получился очень странный ответ.
Именованные параметры
Вообще при разработке приложение очень часто приходится передавать параметры командной строки. Их количество может быть очень большим, десятки параметров вполне обычное дело, и понятно что запомнить их расположение весьма проблематично.
Чтобы бороться с этой проблемой придумали передавать именованные параметры (или как их еще называют флаги).
То есть идея такая вы перед каждым параметром пишете его имя примерно так:
./hello --year 2005 --name "Вася"
и теперь уже на важно в каком порядке вы их передадите, то есть следующий запуск должен сработать также:
./hello --name "Вася" --year 2005
Но как можно догадаться, что если сейчас попробовать это запустить, оно не сработает
Шо же делать?
К счастью для нас, нет необходимости реализовывать эту логику самостоятельно.
Так как задача работы с параметрами очень распространённая, то все уже написано до нас. Осталось только найти нужную библиотечку
Мы воспользуемся либой, которая называется CLI11
Работаем с CLI11
Идем на github https://github.com/CLIUtils/CLI11/releases и качаем файлик
в принципе, можно скопировать ссылку
и как модный хакер, запустить в консольке команду
wget <скопированная ссылка>
увидим такую крипоту
но зато если написать ls -la
то в папке заметим скачанный файлик:
И так, что за это файлик такой? Это обыкновенный C++ файл с кодом для обработки параметров командной строки
Попробуем ей воспользоваться, удалим весь старый код из hello.cpp и напишем
#include <iostream>
#include "CLI11.hpp"
using namespace std;
int main(int argc, char* argv[])
{
// создаем описание нашего приложения
CLI::App app{"Мое приложение"};
// создаем переменную под имя
// со значением по умолчанию "странник"
std::string userName = "странник";
// объявляем параметр командной строки --name
// который привязываем к переменной userName
app.add_option("-n,--name", userName, "имя пользователя");
// запускаем обработчик командной строки
CLI11_PARSE(app, argc, argv);
// к этому моменту в userName будет то имя которое переда юзер
cout << "Привет, " << userName << endl;
return 0;
}
компилируем:
g++ hello.cpp -o hello
можно заметить, что время компиляции заметно возросло.
Тестируем
- смотрите, если запустить его без параметров, то он использует имя по умолчанию, то есть “странник”
- если попробовать передать Васю по старинке, то он ругается, что нельзя передать Вася без имени
- ну а если передать Васю с именованным параметром, то все сработает как надо =)
го делать задание =О