web-dev-qa-db-fra.com

Où sont les paramètres de la fonction principale C / C ++?

En C/C++, la fonction principale reçoit des paramètres de type char*.

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

argv est un tableau de char* et pointe sur des chaînes. Où sont situées ces chaînes? Sont-ils sur le tas, la pile ou ailleurs?

60
remainn

Il s'agit en fait d'une combinaison de dépendance du compilateur et de dépendance du système d'exploitation. main() est une fonction comme n'importe quelle autre fonction C, donc l'emplacement des deux paramètres argc et argv suivra la norme pour le compilateur sur la plate-forme. par exemple. pour la plupart des compilateurs C ciblant x86, ils seront sur la pile juste au-dessus de l'adresse de retour et du pointeur de base enregistré (la pile se développe vers le bas, rappelez-vous). Sur x86_64, les paramètres sont passés dans les registres, donc argc sera dans %edi Et argv sera dans %rsi. Le code dans la fonction principale générée par le compilateur les copie ensuite dans la pile, et c'est là que les références ultérieures pointent. C'est ainsi que les registres peuvent être utilisés pour les appels de fonction à partir de main.

Le bloc de char* Vers lequel pointe argv et les séquences de caractères réelles peuvent être n'importe où. Ils démarreront dans un emplacement défini par le système d'exploitation et peuvent être copiés par le code de préambule que l'éditeur de liens génère sur la pile ou ailleurs. Vous devrez regarder le code de exec() et le préambule de l'assembleur généré par l'éditeur de liens pour le savoir.

17
JeremyP

Ils sont magiques pour le compilateur et dépendent de l'implémentation.

31
Stu

Voici ce que dit la norme C ( n1256 ):

5.1.2.2.1 Démarrage du programme
...
2 S'ils sont déclarés, les paramètres de la principale doit obéir aux contraintes suivantes:

  • La valeur de argc doit être non négatif.

  • argv [argc] doit être un pointeur nul.

  • Si la valeur de argc est supérieur à zéro, les membres du tableau argv [0] à travers argv [argc-1] inclus doit contenir des pointeurs vers des chaînes, qui reçoivent des valeurs définies par l'implémentation par l'environnement hôte 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érieur à zéro, la chaîne pointée par argv [0] représente le nom du programmeargv [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érieur à un, les chaînes pointées par argv [1] à travers argv [argc-1] représenter le paramètres du programme.

  • Les paramètres argc et argv et les cordes pointées par le argv Le tableau doit être modifiable par le programme et conserver ses dernières valeurs stockées entre le démarrage du programme et la fin du programme.

La dernière puce est la plus intéressante où les valeurs de chaîne sont stockées. Il ne spécifie pas de tas ou de pile, mais il nécessite que les chaînes soient accessibles en écriture et aient une étendue statique, ce qui place des limites sur l'endroit où le contenu de la chaîne peut être localisé. Comme d'autres l'ont dit, les détails exacts dépendront de la mise en œuvre.

28
John Bode

La réponse à cette question dépend du compilateur. Cela signifie qu'il n'est pas traité dans la norme C, donc tout le monde peut l'implémenter comme il le souhaite. Ceci est normal car les systèmes d'exploitation n'ont pas non plus de méthode standard acceptée et commune pour démarrer et terminer les processus.

Imaginons un scénario simple, pourquoi pas.

Le processus reçoit par un mécanisme les arguments écrits dans la ligne de commande. argc est alors juste un int qui est poussé vers la pile par la fonction bootstrap que le compilateur a mis comme point d'entrée pour le processus du programme (une partie du runtime). Les valeurs réelles sont get à partir du système d'exploitation, et peut être, par exemple, écrit dans un bloc de mémoire du tas. Ensuite, le vecteur argv est construit et l'adresse à sa première position est également insérée dans la pile.

Ensuite, la fonction main (), qui doit être fournie par le programmeur, est appelée et sa valeur de retour est enregistrée pour une utilisation ultérieure (presque immédiate). Les structures du tas sont libérées et le code de sortie obtenu pour main est exporté vers le système d'exploitation. Le processus se termine.

8
Baltasarq

Ces paramètres ne sont pas différents des paramètres de toute autre fonction. Si la séquence d'appel de l'architecture nécessite que les paramètres passent par la pile, ils sont sur la pile. Si, comme sur, x86-64 certains paramètres vont dans les registres, ils vont aussi dans les registres.

3
horsh

Comme de nombreuses autres réponses le soulignent ici, le mécanisme précis qu'une implémentation de compilateur utilise pour passer des arguments à main n'est pas spécifié par la norme (tout comme le mécanisme utilisé par un compilateur pour passer des arguments à une fonction). À strictement parler, le compilateur n'a même pas besoin de transmettre quoi que ce soit d'utile dans ces paramètres, car les valeurs sont définies par l'implémentation. Mais aucune de ces réponses n'est particulièrement utile.

Le programme C (ou C++) typique est compilé pour ce qui est connu comme un environnement d'exécution 'hébergé' (en utilisant la fonction main() comme point de départ de votre programme est l'une des exigences pour un environnement hébergé). L'essentiel à savoir est que le compilateur organise les choses de telle sorte que lorsque l'exécutable est lancé par le système d'exploitation, le runtime du compilateur prend le contrôle initialement - pas la fonction main(). Le code d'initialisation du runtime effectue toute l'initialisation nécessaire, y compris l'allocation de mémoire pour les arguments à main(), puis il transfère le contrôle à main().

La mémoire pour les arguments de main() pourrait provenir du tas, être allouée sur la pile (éventuellement en utilisant des techniques qui ne sont pas disponibles pour le code C standard), ou pourrait utiliser de la mémoire allouée statiquement, bien que ce soit un option moins probable simplement parce qu'elle est moins flexible. La norme exige que la mémoire utilisée pour les chaînes pointées par argv soit modifiable et que les modifications apportées à ces chaînes persistent pendant toute la durée de vie du programme.

Sachez simplement qu'avant que l'exécution n'atteigne main(), un certain nombre de code a déjà été exécuté qui configure l'environnement dans lequel votre programme doit s'exécuter.

3
Michael Burr

On ne sait généralement pas où ils se trouvent.

#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
  char **foo;
  char *bar[] = {"foo", "bar"};

  (void)argv; /* avoid unused argv warning */

  foo = malloc(sizeof *foo);
  foo[0] = malloc(42);
  strcpy(foo[0], "forty two");

  /* where is foo located? stack? heap? somewhere else? */
  if (argc != 42) main(42, foo); else return 0;

  /* where is bar located? stack? heap? somewhere else? */
  if (argc != 43) main(43, bar); else return 0;
  /* except for the fact that bar elements
  ** point to unmodifiable strings
  ** this call to main is perfectably reasonable */

  return 0;
  /* please ignore memory leaks, thank you */
}
2
pmg

Comme pmg le mentionne, lorsque main est appelé récursivement, c'est à l'appelant que les arguments pointent. Fondamentalement, la réponse est la même sur l'appel d'origine de main, sauf que "l'appelant" est l'implémentation C/OS.

Sur les systèmes UNIX-y, les chaînes vers lesquelles argv pointe, les argv pointent elles-mêmes et les variables d'environnement initiales du processus sont presque toujours stockées tout en haut de la pile.

2
R..

La liste d'arguments fait partie de l'environnement de processus, similaire (mais distincte) aux variables d'environnement.

2
Chris