Todo programa que você roda a partir de um terminal pode receber argumentos: gcc -Wall hello.c -o hello passa quatro deles. Seus próprios programas em C leem os seus por meio de dois parâmetros da main, e esse é o mecanismo inteiro - nenhuma chamada de biblioteca, nenhuma preparação.
A assinatura
Até agora todo exemplo nestes docs usou int main(void). A outra forma padrão recebe a linha de comando:
int main(int argc, char *argv[]) {
/* ... */
}
argc("argument count", contagem de argumentos) é quantos argumentos existem, incluindo o nome do programa.argv("argument vector", vetor de argumentos) é um array de strings.char *argv[]significa "array de ponteiros para char", que é um array de strings C.
char **argv é uma grafia equivalente que você vai ver com a mesma frequência; parâmetros que são arrays decaem para ponteiros, então as duas declaram a mesma coisa.
Use o painel Args do editor para fornecer os argumentos (cada campo é um argumento), e então rode. Experimente três campos: hello, world, 42.
A anatomia
Rodar ./greet Ada Lovelace produz:
| Índice | Valor | |
|---|---|---|
argv[0] | "./greet" | o nome do programa como foi invocado |
argv[1] | "Ada" | primeiro argumento de verdade |
argv[2] | "Lovelace" | segundo argumento de verdade |
argv[3] | NULL | o terminador |
argc | 3 | contagem incluindo argv[0] |
Quatro fatos que vale memorizar:
argcé pelo menos 1 na prática, porqueargv[0]é o nome do programa. Os argumentos de verdade começam no índice 1, que é por que laços sobre eles começam emi = 1.- Tudo é string.
./prog 42te dá"42", os dois caracteres, nunca o número 42. Converter é trabalho seu. argv[argc]éNULL. Garantido pelo padrão, então você pode percorrer o array semargcse preferir:for (char **p = argv + 1; *p != NULL; p++).- O shell separa as palavras, não o seu programa.
./prog "Ada Lovelace"é um argumento; as aspas são consumidas pelo shell e nunca chegam aoargv.
Verifique antes de ler
Um argumento que não foi passado não é uma string vazia - é memória que você não tem o direito de tocar. Sempre valide argc primeiro:
Duas convenções nesse programinha, ambas padrão nas ferramentas Unix:
- A mensagem de uso vai para o
stderr, não para ostdout, para não poluir uma saída que esteja sendo canalizada para outro lugar. - Um retorno diferente de zero da
mainsinaliza falha para quem executou o programa.0significa sucesso; qualquer outra coisa significa que algo deu errado. Scripts de shell verificam isso.
Imprimir argv[0] em vez de um nome fixo faz a mensagem combinar com o jeito como o usuário invocou o programa, mesmo que ele tenha sido renomeado ou alcançado por outro caminho.
Convertendo argumentos numéricos
argv[1] é texto. Para fazer aritmética você precisa convertê-lo, e a função a usar é a strtol de <stdlib.h>:
Adicione 10, 20 e 30 como três campos de Args, depois troque um por banana para ver o caminho de erro.
O terceiro parâmetro de strtol é a base: 10 para decimal, 16 para hexadecimal, ou 0 para detectar automaticamente a partir de um prefixo 0x ou de um zero à esquerda. O segundo é onde guardar um ponteiro para o primeiro caractere que ele não consumiu, e é isso que torna a verificação de erros possível:
end == textsignifica que nada foi lido - o argumento não começava com um número.*end != '\0'significa que sobrou texto depois do número, então"12abc"é rejeitado em vez de virar silenciosamente 12.errno == ERANGEsignifica que o valor estourou olong.
Compare com atoi, que é mais curto e não consegue reportar nada disso:
int n = atoi(argv[1]); /* "banana" -> 0, "0" -> 0, overflow -> indefinido */
atoi retorna 0 para entrada inválida, o que é indistinguível de um zero legítimo. Use strtol (e strtod para ponto flutuante) sempre que a entrada vier de fora do seu programa. Mais em conversão de strings.
Uma pequena calculadora
Juntando tudo - um programa que recebe um número, um operador e um número:
Experimente 12 + 30, depois 7 x 6, depois 5 / 0.
Note strcmp(op, "+") == 0 em vez de op == "+". Comparar valores char * com == compara endereços, não conteúdos, e seria falso mesmo para textos idênticos. Veja funções de string.
O x em vez de * é um detalhe do mundo real: a maioria dos shells expande um * solto na lista de arquivos do diretório atual antes mesmo de o seu programa rodar. Colocá-lo entre aspas ('*') também funciona, mas escolher um caractere que o shell ignora é mais gentil.
Tratando flags
Opções convencionalmente começam com -. Um laço simples feito à mão dá conta dos casos comuns:
Experimente com quatro campos de Args: -v, -n, 3, hello.
A verificação i + 1 >= argc antes de argv[++i] é a linha importante: uma opção que espera um valor precisa confirmar que o valor está realmente lá, ou -n como último argumento lê além do fim do array. Em sistemas Unix de verdade, o getopt de <unistd.h> faz tudo isso por você, incluindo opções curtas agrupadas como -vn3; vale recorrer a ele assim que um programa tem mais de duas ou três flags.
Argumentos no editor do navegador
Os blocos de editor desta página são compilados e executados para você, e o painel Args é onde você digita o que viria depois do nome do programa em um terminal. Cada campo que você adiciona com Add arg vira exatamente uma entrada em argv - não há shell no meio, então nada é separado em espaços e nenhuma aspa é necessária: um campo contendo hello world chega como o único argumento hello world. Para passar -n 3 hello, adicione três campos. Deixar o painel vazio dá argc == 1 - que é por que a guarda argc < 2 dispara na primeira execução, e por que vale escrevê-la.
Erros comuns
- Ler
argv[1]sem verificarargc. Comportamento indefinido quando nenhum argumento foi passado - e o crash mais comum nesta área. - Começar o laço em
i = 0. Isso processa o nome do programa como se fosse dado. - Tratar
argv[1]como número. É texto até você converter. - Usar
atoiem entrada do usuário. Sem jeito de distinguir um argumento ruim de um zero. - Comparar strings com
==. Usestrcmp. - Escrever dentro das strings de
argv. Modificá-las é permitido pelo padrão, mas o espaço é limitado e depende da plataforma; copie para o seu próprio buffer se precisar mudar alguma coisa.
Perguntas frequentes
O que são argc e argv em C?
São os dois parâmetros de int main(int argc, char *argv[]). argc é o número de argumentos de linha de comando, incluindo o nome do programa; argv é um array desses argumentos como strings. argv[0] é o nome do programa, argv[1] é o primeiro argumento de verdade, e argv[argc] é sempre NULL.
Como se passa argumentos para um programa em C?
Digite-os depois do nome do executável no terminal: ./program hello 42. Isso dá argc == 3, com argv[1] sendo a string "hello" e argv[2] a string "42". No editor desta página, os argumentos vão no painel Args em vez de um terminal.
Como converter um argumento de linha de comando em int em C?
Use strtol: char *end; long n = strtol(argv[1], &end, 10); e depois verifique que end não continua apontando para o início (nada foi lido) e que *end é '\0' (sem lixo sobrando). atoi é mais curto, mas retorna 0 tanto para "0" quanto para "banana", então não tem como reportar erro.
O que é argv[0] em C?
O nome com que o programa foi invocado - tipicamente ./program ou o caminho completo. É útil em mensagens de uso (fprintf(stderr, "uso: %s ARQUIVO\n", argv[0])) para que a mensagem combine com o jeito como o usuário realmente chamou o programa. Em casos incomuns pode ser uma string vazia, então não presuma que está presente.