Parametry przekazywane programom podczas uruchomienia mają najczęściej formę kilku przełączników (switches), po których opcjonalnie występują właściwe dla nich argumenty. Zwyczajowo rzeczone przełączniki są poprzedzone myślnikiem (styl uniksowy) lub slashem (styl MS-DOS), jak w przykładzie poniżej:
gcc -c main.c -o main.o -pedantic
Tak skonstruowany wiersz poleceń jest przekazywany przez runtime do aplikacji C/C++ jako tablica ciągów znaków, powstałych już po podzieleniu go na części według spacji i ew. cudzysłowów. Tradycyjnie pierwszy parametr (
argc
) funkcji main
określa liczbę tych części, zaś drugi (argv
) jest wspomnianą tablicą je zawierającą. Warto pamiętać, że – jeśli interesują nas tylko argumenty wywołania – jest to tablica indeksowana od jedynki, gdyż argv[0]
zawiera zawsze samo polecenie uruchamiające program (w powyższym przykładzie byłby to ciąg "gcc"
). Ostatnim elementem jest z kolei argv[argc - 1]
, zatem w sumie tablica zawiera argc - 1
znaczących parametrów programu. Wreszcie, gwarantowane jest, iż argv[argc]
jest zawsze pustym wskaźnikiem, jeśli do czegokolwiek mogłoby się to przydać.
Bezpośrednia interpretacja wiersza poleceń, który używa wspomnianych na początku przełączników, może być jednak nieco kłopotliwa. Wydaje mi się, że lepiej jest przetworzyć ją do bardziej znośnej postaci słownika (mapy), pozwalającego odwoływać się do switchy i ich argumentów po nazwie. Można to zrobić choćby w poniższy sposób:
#include
const char SWITCH_CHAR = ‘-‘; // lub ‘/’
const CommandLine ParseCommandLine(int argc, const char* argv[])
{
CommandLine cl;
for (int i = 1; i < argc; )
if (*(argv[i]) == SWITCH_CHAR)
{
std::vector
p.reserve (argc – i);
int j;
for (j = i + 1;
j < argc && (*(argv[j]) != SWITCH_CHAR || strstr(argv[j], " "));
++j)
p.push_back (argv[j]);
cl.insert (std::make_pair(argv[i] + 1, p));
i = j;
}
else
++i;
return cl;
}[/cpp]
W rezultacie otrzymamy mapę, w której wyszukiwanie (std::map::find
) pozwoli nam określić, czy dany przełącznik był podany, zaś indeksowanie (operator []
) da nam dostęp do jego parametrów w postaci wektora.
Idea przekazywania parametrów w linii komend “od pauzy” jest w UNIXach pewnym standardem, i do parsowania tych poleceń przeznaczona jest specjalna biblioteka, getopt. Pozwala ona też parsować “długie opcje” (longopt), postaci –opcja i –opcja=wartosc.
Nie we wszystkich. W *BSD parametry są często bez znaku “teraz będzie parametr”. np. ps aux i ps -aux robi to samo pod Linuksem (który przyjął obie konwencje).
Niby getopt to fajna biblioteka, ale w praktyce użyłem jej dokładnie raz – żeby zobaczyć jak działa :-) Niestety powoduje “przypisanie” do jednego systemu. Co za różnica czy program jest tylko dla Windowsa czy tylko dla Linuksa?
Multiplatformowo to tylko Boost.Program_options ;) W ostatnim projekcie firmowym z niej korzystam i sprawuje sie calkiem dobrze. Choc mam male problemy, aby dostosowac do swojego specyficznego zachowania ;)
To co opisałeś jest fajne, ale nie obejmuje wszystkich spotykanych przypadków. Niektóre programy mają /Opt=Param albo /Opt:Param. W Uniksach często można też pisać bez spacji, np. zamiast -l biblioteka to -lbiblioteka. Poza tym bardzo często potrzebne są też przełączniki bez parametru albo parametry bez przełącznika (np. nazwy plików wejściowych).
Kiedy używamy main() to mamy już przynajmniej część roboty zrobioną. Gorzej, kiedy używamy WinMain, który dostaje jeden wielki char* CmdLine. Wtedy trzeba samemu sobie rozłożyć łańcuch nawet na poszczególne parametry, a to też nie proste, bo mogą być cudzysłowy.
Parsowanie to w sumie osobny temat. Niezbyt trudny, ale – kto wie? – może wart opisania :)
Co do innych formatów linii komend to oczywiście, takie są. Ale jeśli mówimy o naszym własnym programie, to z definicji możemy sobie takowy wybrać – niekoniecznie musimy supportować wszystkie możliwe i niemożliwe sposoby przekazywania opcji :) Mój sposób obsługuje przełączniki bez parametrów (wtedy lista parametrów jest po prostu pusta), a do parametru bez przełącznika ów przełącznik zawsze można jednak dorobić :)
Witam mam prosty skrypt ale w C/C++ tez chcialbym tego triku uzyc i chyba bez parsowania sie nie obejdzie chodzi o taka sytuacje:
program.exe -b “lancuch znakow z lini komend” > plik.txt (w te strone dziala, ale w druga juz nie)
program.exe -d < plik.txt (zwraca informacje ze jest tylko 1 argument linii polecen)