Résumé du traitement des arguments de ligne de commande en C/C++
Il y a quelque temps, en parcourant le code source du noyau Linux, j'ai remarqué la façon dont le noyau gère les paramètres de module (moduleparam), j'ai trouvé ça plutôt ingénieux, ce qui m'a donné envie d'étudier plus en détail comment traiter de manière plus efficace les paramètres de ligne de commande en C. Le code utilisé dans cet article se trouve ici : aparsingLe code peut être compilé et exécuté sous Windows, Linux et Mac OS X. Les instructions détaillées de compilation se trouvent dans README.md.
getenv
(https://github.com/disenone/aparsing/blob/master/getenv/getenv_test.c)Veuillez traduire ce texte en français :
La fonction getenv
est déclarée comme indiqué au 4Prends le nom de la variable que tu veux obtenir en argument, renvoie la valeur de cette variable. Si la variable n'est pas trouvée, renvoie 0. 10Translate these text into French language:
Et 15Le code consiste à récupérer les valeurs de deux variables d'environnement différentes, puis à afficher la valeur de chaque variable si elle est valide. Il est important de noter que la fonction getenv
renvoie toujours des chaînes de caractères, donc l'utilisateur doit convertir manuellement les valeurs en types numériques, ce qui peut rendre l'utilisation moins pratique. Compilez et exécutez :
Sous Windows :
Sous Linux :
Veuillez traduire ce texte en langue française :
getopt
Linux provides us with a set of functions getopt, getopt_long, getopt_long_only
to handle command line arguments passed into the program. The declarations of these three functions are:
La commande getopt
ne peut traiter que les options courtes (c'est-à-dire les options d'un seul caractère), tandis que getopt_long
et getopt_long_only
peuvent traiter les options longues. Pour une explication détaillée des fonctions, veuillez consulter le manuel de Linux. Nous allons maintenant expliquer l'utilisation de getopt
et getopt_long
à l'aide d'exemples.
Il convient de noter que ces fonctions ne sont pas disponibles sous Windows. J'ai donc recherché une version du code source compilable sous Windows, apporté quelques ajustements mineurs et le code est disponible iciI'm sorry, but it seems that there is no text to translate.
Nous allons nous concentrer sur l'analyse de l'utilisation de getopt_long
. Les trois premiers paramètres de getopt_long
sont les mêmes que pour getopt
: le nombre d'arguments de la ligne de commande argc
, le tableau des arguments de la ligne de commande argv
, et la forme spécifique des options courtes optstring
. Le format de optstring
est composé de caractères d'options courts, suivis d'un deux points :
pour indiquer une option avec argument, de deux deux points ::
pour indiquer une option avec argument facultatif. Par exemple, à la ligne 19, la déclaration des options courtes est la suivante: l'option b
n'a pas d'argument supplémentaire, l'option a
a un argument supplémentaire, et l'option c
a un argument facultatif.
Les deux derniers paramètres de getopt_long
sont utilisés pour traiter les options longues, avec la structure option
étant :
struct option {
const char *nom; // Long name of the parameter
int has_arg; // Whether it has additional arguments
int *flag; // Establishes how to return the function call result
int val; // La valeur renvoyée
};
name
peut toujours être défini à une longueur d'un seul caractère.
Le terme has_arg
peut être défini comme no_argument, required_argument, optional_argument
, qui respectivement signifient sans argument, avec argument requis, avec argument facultatif.
Les flag
et val
sont utilisés ensemble. Si flag = NULL
, getopt_long
retournera directement val
. Sinon, si flag
est un pointeur valide, getopt_long
effectuera une opération similaire à *flag = val
, en définissant la variable pointée par flag
avec la valeur de val
.
Si getopt_long
trouve une correspondance avec un argument court, il renverra la valeur de ce court argument. S'il trouve une correspondance avec un argument long, il renverra val
(flag = NULL
) ou renverra 0
(flag != NULL; *flag = val;
). Si un caractère qui n'est pas un argument est rencontré, il renverra ?
. Lorsque tous les arguments ont été traités, il renverra -1
.
En utilisant les propriétés de la valeur de retour, nous pouvons créer un effet où les longues options et les courtes options ont la même signification, par exemple, en prenant le premier argument de long_options
add
, en définissant sa valeur val
comme le caractère de l'option courte 'a'
, alors lors de la vérification du retour, --add
et -a
seront traités dans la même branche de traitement, et seront considérés comme ayant la même signification.
Le dernier morceau du puzzle est l'utilisation de optind
et optarg
. optind
indique la position du prochain argument à traiter dans argv
, tandis que optarg
pointe vers la chaîne de caractères des arguments supplémentaires.
Compiler et exécuter le code :
$ .\getopt_test -a 1 -b -c4 --add 2 --verbose --verbose=3 -123 -e --e
option a with value '1'
option b
option c with value '4'
option a with value '2'
option verbose
option verbose with arg 3
option 1
option 2
option 3
.\getopt_test: invalid option -- e
.\getopt_test: unrecognized option `--e'
Les significations de -a
et --add
sont identiques. Les arguments optionnels des options courtes sont directement placés après, par exemple -c4
, tandis que les arguments optionnels des options longues doivent être précédés d'un signe égal, par exemple --verbose=3
.
mobuleparam
D'accord, enfin arrivé à la méthode qui a été à l'origine de cet article, le noyau Linux utilise une méthode très astucieuse pour transmettre des paramètres aux modules noyaux, il s'agit de moduleparam
. Je vais d'abord expliquer brièvement la méthode moduleparam
du noyau Linux ici, pour des explications plus détaillées, vous pouvez consulter le code. Bien que j'aie emprunté certaines méthodes de traitement de moduleparam
, il existe quelques différences avec celle du noyau Linux, pour les distinguer, je vais appeler ma méthode small moduleparam
, tandis que celle du noyau Linux continuera d'être appelée moduleparam
.
Consultez d'abord l'utilisation de moduleparam
, déclarez-le dans le module :
Ensuite, lorsque vous chargez le module, saisissez les paramètres d'entrée :
La variable enable_debug
est correctement définie à 1
, ce qui la rend facile à utiliser. Il nécessite peu de code supplémentaire, permettant ainsi d'écrire un code concis et élégant. Il n'est pas nécessaire de faire de nombreux boucles de vérification comme avec getenv
et getopt
, en plus, il inclut déjà la conversion de types. En voyant cela, je me suis dis que si cette méthode pouvait être utilisée pour gérer les arguments de ligne de commande, ce serait encore mieux.
Continuons en examinant la mise en œuvre principale de moduleparam
:
module_param
is a macro that essentially creates a kernel_param
structure that reflects the incoming variable, storing enough information to access and set the variable, as stated in lines 20-24. This structure is placed in a section called __param
(__section__("__param")
). Once the structure is saved, the kernel will locate the position and number of structures in the elf file's section __param
when loading the module, and then set the value of each parameter based on the name and param_set_fn
. The method to locate a specific section
by name is platform-specific. The Linux kernel handles elf files, and Linux provides the readelf
command to view information about elf files. Those interested can refer to the readelf
help documentation.
Traduisez ce texte en langue française :
Le texte ci-dessus mentionne que l'approche du noyau Linux est spécifique à la plate-forme, mais je cherche une méthode qui soit indépendante de la plate-forme pour gérer les paramètres. Par conséquent, nous devons modifier légèrement l'approche initiale de moduleparam
en supprimant la déclaration __section__ ("__param")
, car nous ne souhaitons pas extraire laborieusement la section d'un fichier elf. Regardons maintenant comment utiliser la version modifiée :
Afin de conserver la structure de chaque réflexion, j'ai ajouté une macro init_module_param(num)
pour déclarer l'espace de stockage de la structure, où num
représente le nombre de paramètres. Si le nombre réel de paramètres déclaré dépasse num
, une erreur d'assertion sera déclenchée. La déclaration de module_param
diffère légèrement de l'original, le dernier paramètre indiquant les permissions d'accès a été supprimé, éliminant ainsi le contrôle d'accès. De plus, une nouvelle macro module_param_bool
a été ajoutée pour gérer les variables de type bool
. Cela n'est pas nécessaire dans les versions Linux où le compilateur gcc utilise la fonction intégrée __builtin_types_compatible_p
pour déterminer le type de variable. Malheureusement, cette fonction n'existe pas dans MSVC, donc j'ai dû supprimer cette fonctionnalité et ajouter une macro à la place. module_param_array
et module_param_string
sont utilisés pour traiter respectivement les tableaux et les chaînes de caractères. Ces fonctionnalités existaient déjà dans la version d'origine.
Une fois que les paramètres de la déclaration sont prêts, il est temps de les traiter, en utilisant la macro parse_params
, en passant argc, argv
en arguments. Le troisième paramètre est un pointeur de fonction de rappel pour le traitement des paramètres inconnus, vous pouvez passer NULL
, ce qui interrompra le traitement des paramètres positionnels et renverra un code d'erreur.
Compiler et exécute le code :
.\moduleparam_test.exe error=0 test=101 btest=1 latest=1,2,3 strtest=\"Hello World!\"
Parsing ARGS: error=0 test=101 btest=1 latest=1,2,3 strtest="Hello World!"
find unknown param: error
test = 101
btest = Y
latest = 1,2,3
strtest = Hello World!
On peut voir que les nombres, les tableaux et les chaînes de caractères peuvent être lus et convertis correctement en format. Si un paramètre ne peut pas être converti en format, une erreur sera renvoyée avec des informations pertinentes affichées. En ajoutant simplement quelques lignes de code, nous pouvons facilement lire et traiter les paramètres, ce qui le rend très élégant à utiliser. Pour une mise en œuvre plus détaillée, vous pouvez directement consulter le code ici。
Résumé
Cette fois-ci, nous avons récapitulé les trois méthodes de gestion des arguments de ligne de commande en C/C++ : getenv
, getopt
et moduleparam
. Chaque méthode a ses propres caractéristiques, il sera possible de choisir la méthode appropriée en fonction des besoins réels à l'avenir.
getenv
is a native cross-platform function that can be used directly, but it is also quite primitive and uses environment variables, which may contaminate the environment. It is advisable to clear unnecessary environment variables before each use to prevent contamination from previous settings.
getopt
is natively supported on Linux platforms, not on Windows. To achieve cross-platform usability, inclusion of implementation code is necessary. The parameter passing adheres to Linux's standard command line parameter format, supporting optional parameters. However, its usage can be slightly cumbersome, usually requiring loops and conditional statements to handle different parameters, and it is not very friendly when dealing with numerical parameters.
Le moduleparam
est un outil de traitement des paramètres en ligne de commande inspiré de l'implémentation des moduleparam
dans le noyau Linux. Il est utilisable sur plusieurs plateformes, facile à utiliser, permet la conversion de différents types de paramètres, mais l'inconvénient est que chaque paramètre nécessite une variable correspondante pour le stockage.
Original: https://wiki.disenone.site/fr
This post is protected by CC BY-NC-SA 4.0 agreement, should be reproduced with attribution.
Visitors. Total Visits. Page Visits.
Ce message a été traduit en utilisant ChatGPT, merci de laisser vos commentairesPointer les éventuels oublis.