Os Parâmetros argc, argv e envp

Neste primeiro post, desejo começar com algo extremamente simples, porém fundamental para a programação em linguagem C em ambiente Linux. Os argumentos argcargv e envp contidos na função main() são de imensa importância para a criação e execução de processos, visto que eles recebem informações pertinentes para a execução do programa em questão. Embora, em alguns casos, eles possam ser omitidos sem nenhum prejuízo, é interessante saber utilizá-los corretamente quando se está desenvolvendo códigos mais avançados, pois eles proporcionam algumas facilidades na programação.

Passagem de Argumentos

Quando executamos um programa no terminal, podemos passar alguns argumentos que são esperados pelo programa e que serão utilizados durante a sua execução. Neste caso, o sistema está providenciando algumas facilidades internas para que o usuário passe informações para o programa a ser executado. Por exemplo, quando digitamos no terminal o seguinte comando para listar arquivos e pastas de um diretório:

Estamos invocando o programa ls e passando para ele os argumentos -l, -a e -t. Estes argumentos servem, respectivamente, para mostrar os arquivos e pastas em formato de lista, mostrar arquivos que começam com ponto (e.g. .bashrc) e organizá-los de maneira que os arquivos modificados mais recentemente sejam listados primeiro. Os três argumentos supracitados serão recebidos pelo programa em sua função principal –  a função main() – justamente pelo parâmetro argv. Ou seja, o usuário está enviando informações para o programa, indicando as tarefas que ele deve executar. Devido a estas características, estes argumentos são chamados de argumentos de linha de comando.

Pois bem, o argumento argc (argument count) é do tipo inteiro, logo ele armazena a quantidade de parâmetros repassados em sua chamada. Já o argumento argv (argument values) é um ponteiro para um vetor de strings. É neste parâmetro onde ficarão armazenados os argumentos repassados na linha de comando. Isto quer dizer que mesmo repassando um número para o programa na linha de comando, ele será armazenado em formato de string. Portando, para manipular estes valores dentro do programa, é necessário fazer uma conversão para obter o real valor desejado. Pode-se utilizar, por exemplo, a função atoi(), que converte uma string em inteiro; a função atof(), que converte uma string em ponto flutuante no formato double, ou, ainda, a função atol(), que converte uma string em long int. Vale enfatizar que o valor contido em argc é exatamente o número de argumentos contidos em argv.

Imprimindo os Argumentos Recebidos

Tendo esclarecido os principais pontos sobre os parâmetros argc e argv, vamos à prática. A seguir, veremos três exemplos que mostram como receber, tratar e interpretar os valores repassados como argumentos para o programa. Crie uma pasta em seu computador e baixe os códigos fonte deste artigo digitando o comando abaixo no terminal ou clicando AQUI.

Descompacte os arquivos utilizando o comando tar e uma nova pasta será criada contendo os arquivos de código fonte. Entre nesta pasta e confira o seu conteúdo. Você já terá os três códigos fonte utilizados neste artigo.

O programa a seguir (print_argc_argv.c) é o exemplo mais simples possível. Ele recebe como argumento um texto qualquer e, como resposta, imprime na tela do terminal a quantidade de argumentos recebidos em argc, o nome do executável e cada uma das strings contidas em argv em linhas diferentes.

Compile o código fonte do arquivo print_argc_argv.c e execute-o no terminal:

O resultado deverá ser este:

Aqui jaz um pequeno detalhe: o valor contido em argc será sempre a quantidade de argumentos repassados mais um. Isto acontece porque o parâmetro argv sempre recebe em sua primeira posição o nome do programa que está sendo chamado na linha de comando. Também é possível notar que cada argumento é delimitado por um espaço em branco. Assim, cada palavra do texto é tratada como um argumento diferente. Você pode executar outros testes repassando para o programa textos maiores ou nenhum texto para verificar o seu comportamento.

Validação e Manipulação de Argumentos

Agora, indo em direção a algo mais próximo da realidade, veremos um programa que valida os argumentos recebidos e manipula-os. A validação serve para saber se o usuário repassou todos os argumentos necessários, caso contrário o programa não terá condições de realizar suas tarefas e deve encerrar sua execução. O programa mostrado abaixo (calculo_imc.c) calcula o IMC (Índice de Massa Corpórea) de um determinado indivíduo e imprime no arquivo de saída uma mensagem de acordo com o valor calculado. Para tanto, o programa recebe como argumentos o caminho do arquivo de saída mais a idade, o peso e a altura da pessoa. Vejamos:

Observe que a primeira coisa feita pelo programa é verificar se a quantidade de argumentos recebidos está correta. Na hipótese dela divergir do número esperado, uma mensagem é impressa na saída padrão de erros e o programa finaliza sua execução. Logo após, o programa abre o arquivo de saída e, caso algum erro ocorra, uma mensagem de erro também é impressa e o programa finaliza. Se nada conspirar até aqui, o programa converte as strings contidas em argv e calcula o IMC. Por fim, o programa imprime uma mensagem no arquivo de saída tomando como base o teste feito no valor do IMC.

Compile o código calculo_imc.c, execute-o passando os argumentos corretamente e, depois, confira o conteúdo do arquivo de saída. Se desejar, faça outros testes enviando argumentos em menor e maior quantidade ou tentando criar o arquivo de saída no diretório root.

O resultado no arquivo de saída será:

Bom, segundo o programa, eu preciso trancar a boca… e preciso mesmo! [risos]

Variáveis de Ambiente

Por último e não menos importante, o parâmetro envp (environment pointer) acrescenta a possibilidade de trabalhar com as variáveis de ambiente (e.g. PATH, PWD, USER, SHELL) dentro do programa. Assim como os argumentos mantidos dentro do vetor argv, a função main() pode conter um terceiro parâmetro que armazena todas as variáveis de ambiente do sistema.

Abaixo, está o código de um programa que recebe argumentos de linha de comando e também as variáveis de ambiente, imprimindo todo o conteúdo na tela.

Observe que o parâmetro envp, por ser um ponteiro para um vetor de strings, também pode ser declarado da forma *envp[], assim como o parâmetro argv. No entanto, preferi trabalhar com este parâmetro na forma de ponteiro de ponteiro por achar mais intuitivo.

Compile o código print_argc_argv_envp.c e execute-o no terminal:

A sua saída deverá ser parecida esta:

Não se preocupe se a sua saída for diferente, contendo um número maior ou menor de variáveis de ambiente. Isto depende da sua distribuição do Linux e das configurações do seu ambiente de trabalho.

Conclusão

Tenha em mente que estes parâmetros não ficarão restritos apenas à linha de comando. Mais adiante, irei mostrar como estes argumentos são repassados de um processo pai para o seu processo filho utilizando a família de funções exec(). Este conjunto de chamadas de sistema permite a substituição da imagem de um processo por um executável já existente, tornando a criação de processos muito mais dinâmica.

Por fim, espero que o leitor tenha apreciado este artigo e que seja de grande valia em seu aprendizado. Qualquer dúvida ou sugestão, utilizem a seção de comentários no final desta página ou o formulário na página de Contato . Não se esqueçam de curtir e compartilhar.

Um grande abraço e até a próxima!

Sobre

Jair Junior é Bacharel em Engenharia Eletrônica pela Universidade de Brasília [2014] com ênfase em microeletrônica. Suas especialidades na área são microcontroladores, sistemas embarcados e projeto de hardware. Também possui conhecimentos aprofundados em aplicações web e processamento digital de imagens. Atualmente, é aluno de pós-graduação lato sensu da PUC Minas no curso de Desenvolvimento de Aplicações Web. Ademais, tem como hobbies viajar, praticar esportes na natureza, apreciar cervejas artesanais e escutar um bom e velho rock 'n roll. Para mais detalhes, acesso a página sobre o autor.

Ver todos os posts de

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *