Pourquoi avons-nous besoin de argc alors qu'il y a toujours une valeur nulle à la fin de argv?

117

Il semble que le argv[argc]est toujours NULL, donc je pense que nous pouvons parcourir la liste d'arguments sans argc. Une seule whileboucle fera cela.

S'il y a toujours un NULLà la fin de argv, pourquoi avons-nous besoin d'un argc?

StarPinkER
la source
17
C'est probablement une question de commodité. Donne au programmeur un moyen facile de renflouer plus tôt s'il n'y a pas assez d'arguments, sans boucle. Sinon, nous aurions sûrement des fonctions appelées à int argc(char *argv[])faire exactement ceci :-))
cnicutar
5
Juste pour être clair, ce "\0"n'est pas la même chose que le pointeur NULL ( 0équivaut à NULL en C ++)
Mats Petersson
31
Pourquoi avons-nous besoin que argv [argc] soit NULL si nous avons argc?
Ambroz Bizjak
7
Sinon, comment détermineriez-vous le nombre d'arguments en temps constant?
avakar
4
Ne pensez pas que les balises linux / unix sont appropriées ici, car ce comportement devrait être vrai pour tous les compilateurs dans tous les systèmes d'exploitation.
Darrel Hoffman

Réponses:

106

Oui, argv[argc]==NULLc'est garanti. Voir C11 5.1.2.2.1 Démarrage du programme (je souligne)

S'ils sont déclarés, les paramètres de la fonction principale doivent obéir aux contraintes suivantes:

La valeur d'argc ne sera pas négative. argv [argc] doit être un pointeur nul.

Fournir argcn'est donc pas vital mais reste utile. Entre autres, il permet de vérifier rapidement que le nombre correct d'arguments a été passé.

Edit: La question a été modifiée pour inclure C ++. n3337 draft 3.6.1 La fonction principale dit

2 ... argc doit être le nombre d'arguments transmis au programme depuis l'environnement dans lequel le programme est exécuté. .... La valeur de argc doit être non négative. La valeur de argv [argc] doit être 0 .

Simonc
la source
36
Et argcpourrait être assez grand, parce que la coquille est en train de faire l' expansion (donc dans ls *l' *est dilatée par le shell avant execved' /bin/lsexécutable). Sur mon système, je peux en avoir argcplusieurs centaines de milliers.
Basile Starynkevitch
C'est plutôt cool, cela ne m'est jamais venu à l'esprit puisque j'ai toujours considéré comme argcsuffisant, mais je peux certainement penser à des situations où cette garantie serait pertinente et même requise. +1
Thomas
6
@BasileStarynkevitch Le temps de simplement parcourir un tableau de valeurs de pointeur une fois de plus jusqu'à NULL, pour obtenir le décompte, est minuscule par rapport au temps déjà passé à générer le tableau de pointeurs, et encore plus non pertinent par rapport à l'utilisation réelle de chaque valeur d'argument dans le programme. Et si simplement vérifier si le nombre d'arguments est supérieur à N, il n'est pas nécessaire de parcourir tout le tableau. Pourtant, je suis entièrement d'accord, argcc'était et c'est une bonne chose.
hyde
43

Oui, il argv[argc]est garanti qu'il s'agit d'un pointeur nul. argcest utilisé pour plus de commodité.

Citant l'explication officielle de la justification C99, notez les mots chèque redondant :

Justification de la Norme internationale - Langages de programmation - C §5.1.2.2.1 Démarrage du programme

La spécification de argcet argvcomme arguments pour mainreconnaître une pratique antérieure étendue. argv[argc]doit être un pointeur nul pour fournir un contrôle redondant pour la fin de la liste, également sur la base de la pratique courante.

Yu Hao
la source
19

C'est pour des raisons historiques et pour la compatibilité avec l'ancien code. À l'origine, il n'y avait aucune garantie qu'il existerait un pointeur nul comme dernier élément du tableau argv. Mais l'argc a toujours existé.

zentrunix
la source
... Ce qui est dommage, d'une certaine manière. Si nous l'avions fait int main(char *argv[], int argc, ...), certains programmes pourraient simplement omettre le argcparce qu'ils n'en ont pas besoin. L'opposé (besoin argcmais pas argv) n'est probablement jamais utile dans un vrai programme.
hyde
@hyde: voir le commentaire ci-dessus par Basile Starynkevitch
zentrunix
6

Nous en «avons besoin», car il est requis par diverses normes.

Nous sommes libres d'ignorer complètement la valeur, mais comme il s'agit du premier paramètre de main, nous devons l'avoir dans la liste des paramètres. En C ++ (et probablement les dialectes C non standard), vous pouvez simplement omettre le nom du paramètre, comme cet extrait de code C ++ (facile à convertir en C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

Dans la norme C, avec des paramètres d'avertissement communs, le paramètre non utilisé génère un avertissement, qui peut être corrigé par une instruction comme celle (void)argc;qui entraîne l'utilisation du nom sans générer de code.

argcest agréable à avoir, car sinon, de nombreux programmes devraient parcourir les paramètres pour obtenir le décompte. De plus, dans de nombreux langages de programmation avec des tableaux qui ont une longueur, il n'y a pas de argcparamètre, il y a juste un tableau avec les éléments.

Hyde
la source
La question concerne à la fois C et C ++. En C, le nom du paramètre est obligatoire.