Função main e argumentos de linha de comando

Todos os programas C++ devem ter uma função main. Se você tentar compilar um programa em C++ sem uma função main, o compilador gera um erro. (Bibliotecas de link dinâmico e bibliotecas static não têm uma função main.) A função main é onde o código-fonte começa a execução, mas antes de um programa entrar na função main, todos os membros da classe static sem inicializadores explícitos são definidos como zero. No Microsoft C++, os objetos static globais também são inicializados antes da entrada para main. Várias restrições se aplicam à função main, mas não se aplicam a nenhuma outra função da C++. A função main:

  • Não pode ser sobrecarregada (consulte Sobrecarga de função).
  • Não pode ser declarada como inline.
  • Não pode ser declarada como static.
  • Não pode ter seu endereço usado.
  • Não pode ser chamada pelo programa.

Assinatura de função main

A função main não tem uma declaração, pois é incorporada à linguagem. Se ela tivesse, a sintaxe da declaração para main seria semelhante a esta:

int main();
int main(int argc, char *argv[]);

Se nenhum valor retornado for especificado na main, o compilador fornecerá um valor retornado de zero.

Argumentos de linha de comando padrão

Os argumentos para main permitem a análise conveniente da linha de comando dos argumentos. Os tipos para argc e argv são definidos pela linguagem. Os nomes argc e argv são tradicionais, mas é possível nomeá-los como quiser.

As definições dos argumentos são as seguintes:

argc
Um inteiro que contém a contagem dos argumentos que seguem em argv. O parâmetro argc é sempre maior ou igual a 1.

argv
Uma matriz de cadeias de caracteres terminadas em nulo que representam argumentos de linha de comando inseridos pelo usuário do programa. Por convenção, argv[0] é o comando com que o programa é invocado. argv[1], é o primeiro argumento da linha de comando. O último argumento da linha de comando é argv[argc - 1], sendo que argv[argc] é sempre NULL.

Para obter informações sobre como suprimir o processamento de linha de comando, consulte Personalizar o processamento de linha de comando C++.

Observação

Por convenção, argv[0] é o nome de arquivo do programa. No entanto, no Windows é possível gerar um processo usando CreateProcess. Se você usar o primeiro e o segundo argumentos (lpApplicationName e lpCommandLine), argv[0] não poderá ser o nome do executável. Você pode usar GetModuleFileName para recuperar o nome do executável e seu caminho totalmente qualificado.

Extensões específicas da Microsoft

As seções a seguir descrevem o comportamento específico da Microsoft.

A função wmain e a macro _tmain

Se você criar seu código-fonte para usar charcaracteres largos Unicode, poderá usar o ponto de entrada wmain específico da Microsoft, que é a versão de charcaractere largo de main. Aqui está a sintaxe de declaração efetiva para wmain:

int wmain();
int wmain(int argc, wchar_t *argv[]);

Você também pode usar a _tmain específica da Microsoft, que é uma macro de pré-processador definida em tchar.h. _tmain resolve a main, a menos que _UNICODE esteja definido. Nesse caso, _tmain resolve a wmain. A macro _tmain e outras macros que começam com _t são úteis para o código que deve compilar versões separadas para conjuntos de charcaracteres estreitos e largos. Para obter mais informações, consulte Usar mapeamentos de texto genérico.

Retornar void de main

Como alternativa, as funções main e wmain podem ser declaradas como void retornado (nenhum valor de retorno). Essa extensão também está disponível em alguns outros compiladores, mas seu uso não é recomendado. Ele fica disponível para simetria quando main não retorna um valor.

Se você declarar main ou wmain como void retornado, não poderá retornar um código exit para o processo pai ou o sistema operacional usando uma instrução return. Para retornar um código exit quando main ou wmain é declarado como void, você deve usar a função exit.

O argumento da linha de comando envp

As assinaturas main ou wmain permitem uma extensão opcional específica da Microsoft para acesso a variáveis de ambiente. Essa extensão também é comum em outros compiladores para sistemas Windows e UNIX. O nome envp é tradicional, mas você pode nomear o parâmetro de ambiente como quiser. Aqui estão as declarações efetivas para as listas de argumentos que incluem o parâmetro de ambiente:

int main(int argc, char* argv[], char* envp[]);
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

envp
O parâmetro opcional envp é uma matriz de cadeias de caracteres representando as variáveis definidas no ambiente do usuário. Essa matriz é encerrada por uma entrada NULL. O parâmetro pode ser declarado como uma matriz de ponteiros para char (char *envp[]) ou como um ponteiro para ponteiros para char (char **envp). Se o programa usa wmain em vez de main, use o tipo de dados wchar_t em vez de char.

O bloco de ambiente passado para main e wmain é uma cópia "congelada" do ambiente atual. Se você alterar posteriormente o ambiente fazendo uma chamada para putenv ou _wputenv, o ambiente atual (conforme retornado por getenv ou _wgetenv e a variável _environ ou _wenviron) será alterado, mas o bloco para o qual envp aponta não será alterado. Para obter mais informações sobre como suprimir o processamento de ambiente, consulte Personalizar o processamento de linha de comando C++. O argumento envp é compatível com o padrão C89, mas não com padrões C++.

Argumentos de exemplo para main

O exemplo a seguir mostra como usar os argumentos argc, argv e envp para main:

// argument_definitions.cpp
// compile with: /EHsc
#include <iostream>
#include <string.h>

using namespace std;
int main( int argc, char *argv[], char *envp[] )
{
    bool numberLines = false;    // Default is no line numbers.

    // If /n is passed to the .exe, display numbered listing
    // of environment variables.
    if ( (argc == 2) && _stricmp( argv[1], "/n" ) == 0 )
         numberLines = true;

    // Walk through list of strings until a NULL is encountered.
    for ( int i = 0; envp[i] != NULL; ++i )
    {
        if ( numberLines )
            cout << i << ": "; // Prefix with numbers if /n specified
        cout << envp[i] << "\n";
    }
}

Analisando argumentos de linha de comando C++

As regras de análise de linha de comando usadas pelo código C/C++ da Microsoft são específicas da Microsoft. O código de inicialização de runtime usa essas regras ao interpretar os argumentos dados na linha de comando do sistema operacional:

  • Os argumentos são delimitados por espaço em branco, que é um espaço ou uma tabulação.

  • O primeiro argumento (argv[0]) é tratado de maneira especial. Ele representa o nome do programa. Como deve ser um nome de caminho válido, as partes cercadas por aspas duplas (") são permitidas. As aspas duplas não são incluídas na saída de argv[0]. As partes cercadas por aspas duplas impedem a interpretação de um charcaractere de espaço ou tabulação como o fim do argumento. As regras posteriores nesta lista não se aplicam.

  • Uma cadeia de caracteres cercada por aspas duplas é interpretada como um único argumento, que pode conter charcaracteres de espaço em branco. Uma cadeia de caracteres entre aspas pode ser inserida em um argumento. O acento circunflexo (^) não é reconhecido como um charcaractere de escape ou delimitador. Dentro de uma cadeia de caracteres entre aspas, um par de aspas duplas é interpretado como um único sinal de aspas duplas escapado. Se a linha de comando terminar antes que um sinal de aspas duplas de fechamento seja localizado, todos os charcaracteres lidos até então serão emitidos como o último argumento.

  • Aspas duplas precedidas por uma barra invertida (\") são interpretadas como um caractere literal de aspas duplas (").

  • As barras invertidas são interpretadas literalmente, a menos que precedam imediatamente as aspas duplas.

  • Se um número par de barras invertidas for seguido por aspas duplas, uma barra invertida (\) será colocada na matriz argv para cada par de barras invertidas (\\), e as aspas duplas (") serão interpretadas como um delimitador de cadeia de caracteres.

  • Se um número ímpar de barras invertidas for seguido por aspas duplas, então uma barra invertida (\) será colocada na matriz argv para cada par de barras invertidas (\\). O sinal de aspas duplas é interpretado como uma sequência de escape pela barra invertida mainrestante, fazendo com que uma marca de aspa dupla literal (") seja colocada em argv.

Exemplo de análise de argumentos de linha de comando

O programa a seguir demonstra como argumentos de linha de comando são passados:

// command_line_arguments.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
int main( int argc,      // Number of strings in array argv
          char *argv[],   // Array of command-line argument strings
          char *envp[] )  // Array of environment variable strings
{
    int count;

    // Display each command-line argument.
    cout << "\nCommand-line arguments:\n";
    for( count = 0; count < argc; count++ )
         cout << "  argv[" << count << "]   "
                << argv[count] << "\n";
}

Resultados da análise de linhas de comando

A tabela a seguir mostra exemplos de entrada e saídas esperadas, demonstrando as regras na lista acima.

Entrada de linha de comando argv[1] argv[2] argv[3]
"abc" d e abc d e
a\\b d"e f"g h a\\b de fg h
a\\\"b c d a\"b c d
a\\\\"b c" d e a\\b c d e
a"b"" c d ab" c d

Expansão de curinga

Opcionalmente, o compilador da Microsoft permite que você use caracteres curingachar, o ponto de interrogação (?) e o asterisco (*) para especificar argumentos de nome de arquivo e de caminho na linha de comando.

Os argumentos de linha de comando são tratados por uma rotina interna no código de inicialização de runtime que, por padrão, não expande curingas em cadeias de caracteres separadas na matriz de cadeia de caracteres argv. Você pode habilitar a expansão de curinga incluindo o arquivo setargv.obj (arquivo wsetargv.obj para wmain) nas opções do compilador do /link ou na linha de comando do LINK.

Para obter mais informações sobre as opções do vinculador de inicialização de runtime, consulte Opções de vinculação.

Personalizar o processamento de linha de comando C++

Se o programa não usa argumentos de linha de comando, você pode suprimir a rotina de processamento de linha de comando para economizar uma pequena quantidade de espaço. Para suprimir seu uso, inclua o arquivo noarg.obj (para main e wmain) nas opções do compilador /link ou na linha de comando LINK.

Da mesma forma, se você nunca acessa a tabela de ambiente pelo argumento envp, é possível suprimir a rotina interna de processamento de ambiente. Para suprimir seu uso, inclua o arquivo noenv.obj (para main e wmain) nas opções do compilador /link ou na linha de comando LINK.

O programa poderá fazer chamadas para a família de rotinas spawn ou exec na biblioteca de runtime C. Se esse for o caso, você não deverá suprimir a rotina de processamento de ambiente, pois essa rotina será usada para passar um ambiente do processo pai para o processo filho.

Confira também

Conceitos básicos