web-dev-qa-db-fra.com

Pourquoi l'argc n'est-il pas une constante?

int main( const int argc , const char[] const argv)

Comme C++ efficace l'article # 3 indique "Utilisez const autant que possible", je commence à penser "pourquoi ne pas faire ces paramètres" constants "const" ?.

Existe-t-il un scénario dans lequel la valeur de argc est modifiée dans un programme?

102
Dinushan

Dans ce cas, l'histoire est un facteur. C a défini ces entrées comme "non constantes", et la compatibilité avec (une bonne partie du) code C existant était l'un des premiers objectifs du C++.

Certaines API UNIX, telles que getopt, manipulent en fait argv[], donc ça ne peut pas être fait const pour cette raison aussi.

(À part: Fait intéressant, bien que le prototype de getopt suggère qu'il ne modifiera pas argv[] mais peut modifier les chaînes pointées, la page de manuel Linux indique que getopt permute ses arguments, et il semble qu'ils savent qu'ils sont méchants . La page de manuel de l'Open Group ne mentionne pas cette permutation.)

Mettre const sur argc et argv n'achèterait pas grand-chose et invaliderait certaines pratiques de programmation à l'ancienne, telles que:

// print out all the arguments:
while (--argc)
    std::cout << *++argv << std::endl;

J'ai écrit de tels programmes en C, et je sais que je ne suis pas seul. J'ai copié l'exemple de quelque part .

113
Joe Z

La norme C (ISO/IEC 9899: 2011) dit:

5.1.2.2.1 Démarrage du programme

¶1 La fonction appelée au démarrage du programme est nommée main. L'implémentation ne déclare aucun prototype pour cette fonction. Il doit être défini avec un type de retour de int et sans paramètres:

int main(void) { /* ... */ }

ou avec deux paramètres (appelés ici argc et argv, bien que tous les noms puissent être utilisés, car ils sont locaux à la fonction dans laquelle ils sont déclarés):

int main(int argc, char *argv[]) { /* ... */ }

ou équivalent;dix) ou d'une autre manière définie par l'implémentation.

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

  • La valeur de argc doit être non négative.
  • argv[argc] doit être un pointeur nul.
  • Si la valeur de argc est supérieure à zéro, les membres du tableau argv[0] par argv[argc-1] inclus doit contenir des pointeurs vers des chaînes, auxquelles l'environnement hôte a donné des valeurs définies par l'implémentation avant le démarrage du programme. L'intention est de fournir au programme des informations déterminées avant le démarrage du programme depuis un autre endroit de l'environnement hébergé. Si l'environnement hôte n'est pas capable de fournir des chaînes avec des lettres en majuscules et en minuscules, la mise en œuvre doit garantir que les chaînes sont reçues en minuscules.
  • Si la valeur de argc est supérieure à zéro, la chaîne pointée par argv[0] représente le nom du programme; argv[0][0] doit être le caractère nul si le nom du programme n'est pas disponible dans l'environnement hôte. Si la valeur de argc est supérieure à un, les chaînes pointées par argv[1] par argv[argc-1] représente les paramètres du programme.
  • Les paramètres argc et argv et les chaînes pointées par le tableau argv doivent être modifiables par le programme et conserver leurs dernières valeurs stockées entre le démarrage et la fin du programme.

dix) Ainsi, int peut être remplacé par un nom de type défini comme int, ou le type de argv peut être écrit comme char **argv, etc.

Notez la dernière puce. Il indique que argc et argv doivent être modifiables. Ils ne doivent pas être modifiés, mais ils peuvent être modifiés.

36
Jonathan Leffler

argc n'est normalement pas une constante car la signature de fonction pour main() est antérieure à const.

Comme argc est une variable de pile, sa modification n'affectera rien d'autre que votre propre traitement en ligne de commande.

Vous êtes bien sûr libre de le déclarer const si vous le souhaitez.

23
razeh

Un niveau supérieur const sur un argument formel ne fait pas partie du type de fonction. Vous pouvez l'ajouter ou le supprimer à votre guise: cela n'affecte que ce que vous pouvez faire avec l'argument dans l'implémentation de la fonction.

Donc pour argc vous pouvez ajouter librement ajouter un const.

Mais pour argv, vous ne pouvez pas créer les données de caractère const sans changer la signature de la fonction. Ce qui signifie qu'il ne s'agit alors pas d'une des signatures de fonction main standard et qu'il ne sera pas nécessaire de la reconnaître comme fonction main. Donc, ce n'est pas une bonne idée.


Une bonne raison pour ne pas utiliser les arguments standard main dans les programmes non-jouets est que dans Windows, ils ne sont pas en mesure de représenter les arguments de programme réels tels que les noms de fichiers avec des caractères internationaux. C'est parce que dans Windows, ils sont par convention très forts encodés en tant que Windows ANSI. Dans Windows, vous pouvez implémenter une fonction d'accès aux arguments plus portable en termes de la fonction API GetCommandLine.


En résumé, rien ne vous empêche d'ajouter const à argc, mais le const- plus utile sur argv vous donnerait un _ non standard main, probablement non reconnue comme telle. Heureusement (de façon ironique) il y a de bonnes raisons de ne pas utiliser les arguments standard main pour le code sérieux portable. Tout simplement, pour la pratique, ils ne prennent en charge que les anciens ASCII, avec uniquement des lettres de l'alphabet anglais.

8

La signature de main est en quelque sorte un artefact historique de C. Historiquement, C n'avait pas const.

Cependant, vous pouvez déclarer votre paramètre const car les effets de const sont uniquement à la compilation.

4
George

Parce que argc est une variable locale (et, en C++, pas une référence ou quelque chose), et parce que l'emplacement spécial de main signifie que les manigances de compatibilité descendante lui accordent une énorme marge de manœuvre sans raison impérieuse de forcer les applications à le rendre constant.

main() {}

int main() {}

main() { return 0; }

main(int argc, char* argv[]) { return 0; }

int main(const int argc, const char** argv) { /* no return*/ }

ceux-ci et bien d'autres variantes seront compilés sur une large gamme de compilateurs C et C++.

Donc, en fin de compte, ce n'est pas que l'argc n'est pas const, juste qu'il ne doit pas l'être, mais cela peut l'être si vous le souhaitez.

http://ideone.com/FKldHF , exemple C:

main(const int argc, const char* argv[]) { return 0; }

http://ideone.com/m1qc9c , exemple C++

main(const int argc) {}
2
kfsone

Mis à part les raisons historiques, une bonne raison de conserver argc et argv non -const est que l'implémentation du compilateur ne sait pas ce que vous allez faire avec les arguments à main, il sait juste qu'il doit vous donner ces arguments.

Lorsque vous définissez vos propres fonctions et les prototypes associés, vous savez quels paramètres vous pouvez créer const et lesquels votre fonction va modifier.

Poussé à l'extrême, vous pourriez déclarer que tous les paramètres de toutes les fonctions devraient être déclarés const, puis si vous aviez une raison de les changer (par exemple décrémenter un index pour rechercher dans un tableau), vous auriez pour créer des variables locales nonconst et copier les valeurs des arguments const dans ces variables. Cela rend le travail occupé et le LOC supplémentaire sans réel avantage. Un analyseur statique décent reprendra si vous ne modifiez pas la valeur d'un argument, et vous recommande de faire le paramètre const.

1
Sam Skuce