Stoa :: C/C++ :: Blog :: Argumentos de entrada (argc e argv)

setembro 03, 2010

user icon

Como usar argumentos na linha de comando em C/C++?

Vejamos alguns exemplos de um sistema GNU/Linux.

Primeiro: o comando ls lista o conteúdo de um diretório no GNU/Linux.

rborges@bio03:~/Desktop$ ls
alsa-driver-1.0.23  alsa-driver-1.0.23.tar.bz2  ati-driver-installer-10-7-x86.x86_64.run  firefox-3.6.8.tar.bz2  questionaire-glite32-V2.odt  virtualbox-3.2_3.2.8-64453~Debian~lenny_amd64.deb

Existem muitos parâmetros que podemos "passar" para o ls, e basta para isso adicionar o argumento após o nome do comando, separando com espaços. Por exemplo, -l mostra a listagem em formato longo:

rborges@bio03:~/Desktop$ ls -l
total 161676
drwxr-xr-x 28 root    root         4096 2010-08-24 22:19 alsa-driver-1.0.23
-rw-r--r--  1 rborges rborges   3337645 2010-08-24 22:15 alsa-driver-1.0.23.tar.bz2
-rwxr--r--  1 rborges rborges 101178081 2010-08-23 06:40 ati-driver-installer-10-7-x86.x86_64.run
-rw-r--r--  1 rborges rborges  10624411 2010-08-25 07:11 firefox-3.6.8.tar.bz2
-rw-r--r--  1 rborges rborges     48684 2010-09-02 06:25 questionaire-glite32-V2.odt
-rw-r--r--  1 rborges rborges  50178030 2010-08-25 21:13 virtualbox-3.2_3.2.8-64453~Debian~lenny_amd64.deb

Outro parãmetro é o -h, que mostra o tamanho dos arquivos em formato apropriado para humanos:

rborges@bio03:~/Desktop$ ls -l -h
total 158M
drwxr-xr-x 28 root    root    4.0K 2010-08-24 22:19 alsa-driver-1.0.23
-rw-r--r--  1 rborges rborges 3.2M 2010-08-24 22:15 alsa-driver-1.0.23.tar.bz2
-rwxr--r--  1 rborges rborges  97M 2010-08-23 06:40 ati-driver-installer-10-7-x86.x86_64.run
-rw-r--r--  1 rborges rborges  11M 2010-08-25 07:11 firefox-3.6.8.tar.bz2
-rw-r--r--  1 rborges rborges  48K 2010-09-02 06:25 questionaire-glite32-V2.odt
-rw-r--r--  1 rborges rborges  48M 2010-08-25 21:13 virtualbox-3.2_3.2.8-64453~Debian~lenny_amd64.deb

Uma outra técnica sobre parâmetros é que você muitas vezes precisa usar duas variáveis para um parâmetro: a primeira especifica a variável, a segunda o valor. Para o exemplo, vou usar o ping, que é um programa que manda um pacote de dados para uma máquina da rede e imprime quanto tempo levou para obter umna resposta.

rborges@bio03:~/Desktop$ ping www.google.com.br
PING www.l.google.com (173.194.34.104) 56(84) bytes of data.
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=1 ttl=54 time=179 ms
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=2 ttl=53 time=182 ms
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=3 ttl=52 time=178 ms
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=4 ttl=52 time=178 ms
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=5 ttl=52 time=178 ms
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=6 ttl=54 time=178 ms
^C
--- www.l.google.com ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5018ms
rtt min/avg/max/mdev = 178.139/179.419/182.864/1.580 ms

Note que precisei usar o Control+c para terminar o programa - ele por default roda infinitamente. (Quando se pára um programa com Control+c em GNU/Linux, em geral aparace a string "^C" na saída do programa).

Então vou usar o parâmetro -c, que especifica uma contagem de vezes a se pingar a outra maquina, e exige um valor numérico no parâmetro seguinte.

rborges@bio03:~/Desktop$ ping www.google.com.br -c 1
PING www.l.google.com (173.194.34.104) 56(84) bytes of data.
64 bytes from lga15s15-in-f104.1e100.net (173.194.34.104): icmp_seq=1 ttl=52 time=178 ms

--- www.l.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 178.929/178.929/178.929/0.000 ms

Agora o ping só manda um pacote e imprime o resultado. Se eu tentar usar só o -c, sem um valor, ou com um valor inválido, uma boa implementação do ping irá gerar uma mensagem de erro (uma má implementação vai travar seu micro e exigir que você reboote ;)

rborges@bio03:~/Desktop$ ping -c
ping: option requires an argument -- c
Usage: ping [-LRUbdfnqrvVaA] [-c count] [-i interval] [-w deadline]
            [-p pattern] [-s packetsize] [-t ttl] [-I interface or address]
            [-M mtu discovery hint] [-S sndbuf]
            [ -T timestamp option ] [ -Q tos ] [hop1 ...] destination
rborges@bio03:~/Desktop$ ping -c um_monte_de_vezes
ping: bad number of packets to transmit.

A pergunta agora é: como fazer a mesma coisa nos meus programas em C/C++?

Resposta: usando as variáveis argc e argv.

(Dica: para procurar outros documentos sobre esse tópico no Google, pesquise "c cpp argc argv")

Estas variáveis são variáveis da função main. Até onde sei, a maneira de implementá-las é sempre a mesma:

int main(int argc, char** argv)

argc é o número de argumentos passados na linha de comando - creio que o nome vem do inglês "argument count" - " contagem de argumentos".

argv é um vetor de ponteiros (por isso a dupla indireção com dois asteriscos) e contém o texto dos argumentos passados - creio queo nome vem do inglês "argument vector" - "vetor de argumentos".

Um exemplo bem simples, que apenas imprime os argumentos:

#include <iostream>

int main(int argc, char** argv) {

    for(int i=0;i<argc;i++)

        std::cout << "argv[" << i << "] = " << argv[i] << std::endl;

    return 0; }

E algumas execuções:

rborges@bio03:~emacs exemplo-argcargv.cpp
rborges@bio03:~/Desktop$ g++ -o exemplo exemplo-argcargv.cpp
rborges@bio03:~/Desktop$ ./exemplo
argv[0] = ./exemplo
rborges@bio03:~/Desktop$ ./exemplo opcao1
argv[0] = ./exemplo
argv[1] = opcao1
rborges@bio03:~/Desktop$ ./exemplo opcao1 op2
argv[0] = ./exemplo
argv[1] = opcao1
argv[2] = op2
rborges@bio03:~/Desktop$ ./exemplo opcao1 op2       op3
argv[0] = ./exemplo
argv[1] = opcao1
argv[2] = op2
argv[3] = op3
rborges@bio03:~/Desktop$ ./exemplo -1 --2 ---3 ----4
argv[0] = ./exemplo
argv[1] = -1
argv[2] = --2
argv[3] = ---3
argv[4] = ----4

Note que o argv[0] é sempre o comando com que o usuário executou o programa.

Creio que vou finalizar este post com a questão "mas pra quê serve isso?"

Bem, certamente se a intenção é escrever um programa com interface gráfica, aonde a entrada de dados é feita pelo usuário, há pouca oportunidade de usar este recurso.

Mas para quem escreve programas que rodam da linha de comando, ou programas que são executados primordialmente por outro programa, este recurso é a maneira mais simples de passar dados entre um programa e outro.

Exercício: escreva um programa que recebe uma string e imprime essa string n vezes, sendo que n é um parâmetro da linha de comando.

Exercício: aprimore o programa do exercício anterior para que receba dois parâmetros: n (número de vezes para imprimir a string) e b (número de espaços em branco a imprimir antes da string).

Exercício: aprimore o programa do exercício anterior para que possa receber os dois parâmetros em qualquer ordem.

Palavras-chave: argc, argumentos, argv, CLI, linha de comando, ls, parâmetros, ping

Postado por Renato Callado Borges em C/C++

Você deve entrar no sistema para escrever um comentário.

Termo de Responsabilidade

Todo o conteúdo desta página é de inteira responsabilidade do usuário. O Stoa, assim como a Universidade de São Paulo, não necessariamente corroboram as opiniões aqui contidas.