HOWTO · C++

Gérer les arguments à l'aide de getopt en C++

Cet article montre comment utiliser la fonction getopt() en C++ pour traiter les arguments.

Sur cette page

Pour analyser les options courtes de la ligne de commande en C++, appelez la fonction POSIX getopt avec argc, argv et un optstring qui déclare chaque option et indique si elle attend une valeur. Utilisez optarg pour lire les valeurs des options et optind pour accéder aux arguments positionnels restants. Si le programme doit aussi accepter des options longues comme --help, utilisez getopt_long.

Comprendre getopt en C++

getopt est spécifiée par POSIX et est couramment disponible sur les systèmes de type Unix ; elle ne fait pas partie de la bibliothèque standard C++. Sur les systèmes qui le fournissent, incluez <unistd.h>. La fonction lit argc et argv et renvoie une option analysée à chaque appel. Une option courte est composée d’un seul caractère, comme -v ; une valeur peut suivre une option, comme dans -o report.txt. getopt n’analyse que les options courtes : un élément tel que --output nécessite donc une autre interface. Consultez la spécification POSIX de getopt pour connaître son interface et les règles de retour.

La disponibilité et certains détails, comme l’ordre des arguments, varient selon la plateforme. Lorsque la portabilité est importante, vérifiez les en-têtes et la documentation du système cible. Les exemples ci-dessous utilisent des interfaces POSIX et un compilateur C++ tel que g++.

Définir les options courtes et analyser les arguments

Un optstring énumère les options acceptées, chacune représentée par un seul caractère. Un caractère suivi de : indique que l’option attend une valeur, que getopt fournit dans optarg. Dans l’exemple, v est une option booléenne et o: accepte un chemin de sortie. Le programme affiche également la valeur positionnelle qui reste après l’analyse. Enregistrez le fichier sous le nom main.cpp ; sur un système de type POSIX, compilez-le avec g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o app.

Exécutez cet exemple :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

#include <iostream>
#include <unistd.h>

int main() {
    char app[] = "app";
    char verbose_option[] = "-v";
    char output_option[] = "-o";
    char output_path[] = "report.txt";
    char input_path[] = "input.csv";
    char* arguments[] = {app, verbose_option, output_option, output_path, input_path, nullptr};
    int argument_count = 5;
    bool verbose = false;
    const char* output = "result.txt";
    int option = 0;

    opterr = 0;
    while ((option = getopt(argument_count, arguments, ":vo:")) != -1) {
        switch (option) {
            case 'v':
                verbose = true;
                break;
            case 'o':
                output = optarg;
                break;
            case ':':
                std::cerr << "Option -" << static_cast<char>(optopt) << " requires a value\n";
                return 2;
            case '?':
            default:
                std::cerr << "Unknown option: -" << static_cast<char>(optopt) << '\n';
                return 2;
        }
    }

    std::cout << "verbose=" << (verbose ? "on" : "off") << '\n';
    std::cout << "output=" << output << '\n';
    for (int i = optind; i < argument_count; ++i) {
        std::cout << "input=" << arguments[i] << '\n';
    }
}
verbose=on
output=report.txt
input=input.csv

Le tableau fixe d’arguments rend l’exemple autonome ; dans un programme réel, transmettez à la fonction les valeurs argc et argv reçues par main. L’optstring :vo: commence par deux-points afin de distinguer une valeur obligatoire manquante d’une option inconnue : v ne prend pas de valeur, tandis que o: en exige une. Les deux formes -o report.txt et -oreport.txt sont généralement acceptées. optarg pointe vers la valeur associée à l’option en cours de traitement.

Gérer les erreurs et les arguments restants

En règle générale, getopt renvoie -1 lorsque l’analyse des options est terminée. Pour une option inconnue, elle renvoie ? ; pour la valeur manquante d’une option qui en exige une, elle renvoie également ?, sauf si l’optstring commence par :. Avec cette convention du deux-points initial, une valeur manquante entraîne le retour de :, tandis qu’une option inconnue entraîne toujours le retour de ?. optopt indique le caractère de l’option concernée. L’exemple d’options courtes suit cette convention et définit opterr à 0 : son switch affiche donc un seul message d’erreur et renvoie un code différent de zéro dans les deux cas. Sans le deux-points initial, les deux erreurs renvoient ? et le code appelant ne peut pas les distinguer à partir de la seule valeur de retour. Ce réglage de opterr désactive également le message d’erreur produit par la bibliothèque.

Après l’analyse, optind contient l’indice du premier argument restant. Parcourez les éléments de optind à argc pour traiter les noms de fichiers ou les autres valeurs positionnelles. Certaines implémentations réordonnent les options et les opérandes pendant l’analyse ; d’autres s’arrêtent au premier opérande ou proposent différents réglages pour contrôler cet ordre. Ne supposez pas que toutes les plateformes traitent de la même façon les options mêlées aux arguments positionnels.

Utiliser getopt_long pour les options longues

Sur les systèmes qui fournissent l’extension GNU <getopt.h>, getopt_long reconnaît les noms longs en plus des options courtes ; cette fonction n’est spécifiée ni par POSIX ni par la bibliothèque standard C++. Le manuel de la bibliothèque C GNU sur getopt_long décrit cette extension et son tableau struct option. Chaque entrée indique un nom long, si l’option n’accepte aucune valeur ou attend une valeur obligatoire ou facultative, ainsi que la valeur renvoyée au switch. La dernière entrée, dont le nom est nul, marque la fin du tableau. Cet exemple autonome accepte --help et --output FILE, ainsi que leurs formes courtes :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

#include <getopt.h>
#include <iostream>

int main() {
    char app[] = "app";
    char help_option[] = "--help";
    char* arguments[] = {app, help_option, nullptr};
    int argument_count = 2;
    const option long_options[] = {
        {"help", no_argument, nullptr, 'h'},
        {"output", required_argument, nullptr, 'o'},
        {nullptr, 0, nullptr, 0}
    };
    const char* output = "result.txt";
    int option = 0;

    opterr = 0;
    while ((option = getopt_long(argument_count, arguments, ":ho:", long_options, nullptr)) != -1) {
        switch (option) {
            case 'h':
                std::cout << "Usage: app [-h] [-o FILE] [FILE...]\n";
                break;
            case 'o':
                output = optarg;
                break;
            case ':':
                std::cerr << "Option requires a value\n";
                return 2;
            case '?':
            default:
                std::cerr << "Unknown option\n";
                return 2;
        }
    }

    std::cout << "output=" << output << '\n';
    for (int i = optind; i < argument_count; ++i) {
        std::cout << "input=" << arguments[i] << '\n';
    }
}
Usage: app [-h] [-o FILE] [FILE...]
output=result.txt

Dans un véritable programme en ligne de commande, utilisez les valeurs argc et argv de main et compilez avec g++ -std=c++17 -Wall -Wextra -pedantic main.cpp -o app sur un système qui fournit getopt_long. L’entrée fixe de l’exemple sélectionne le chemin d’aide ; remplacez-la par --output report.txt input.csv pour choisir un chemin de sortie et laisser input.csv à traiter à l’aide de optind. Vérifiez la plateforme cible avant de dépendre de cette extension.