2009-10-15 6 views
4

Je voulais savoir pourquoi la violation d'accès se produit pour cout et dépassement de pile pour printf dans les deux extraits de code suivants.Pourquoi une violation d'accès pour cout et dépassement de pile pour printf

Je voulais savoir pourquoi la violation d'accès pour le premier code au lieu du dépassement de pile.

premier code que je reçois une violation d'accès:

void Test(); 

void Test() 
{ 
    static int i = 0; 
     cout << i++ << endl;  
    Test(); 
} 
int main() 
{ 

    Test(); 

    return 0; 
} 

deuxième code que je Get Stack Overflow:

void Test(); 

void Test() 
{ 
    static int i = 0; 
     printf("%d\n", i++);  
    Test(); 
} 
int main() 
{ 

    Test(); 

    return 0; 
} 

réponse sera très appréciée.

Merci à l'avance

+1

Avez-vous inclus les fichiers d'en-tête corrects? – Toad

+10

Hmmm ... vous demandez pourquoi le premier exemple donne une violation d'accès au lieu d'un débordement de pile et en réponse tout le monde vous dit pourquoi le second exemple donne un débordement de pile. Intéressant comment tout le monde répond à la question perçue qu'ils connaissent la réponse à la place de la question que vous demandez réellement. –

+0

D'accord avec Paul. –

Répondre

18

Je suppose que vous comprenez que les deux fonctions se bloquent en raison de l'épuisement de la pile après une tentative de récursion infinie. Je pense que ce que vous demandez est: pourquoi l'exemple de cout ne plante pas avec "Stack Overflow" aussi?

Je ne pense pas que la réponse a à voir avec la détection par le compilateur de la récurrence de la queue. Si le compilateur a optimisé la récursivité, aucun exemple ne doit tomber en panne.

J'ai une idée de ce qui se passe. L'exception "Stack Overflow" est implémentée dans certains cas (par exemple, Windows) avec une "page de garde" de mémoire virtuelle unique allouée à la fin de la pile. Lorsqu'un accès de pile frappe cette page de garde, un type d'exception spécial est généré.

Étant donné que la page de petite granularité d'Intel a une longueur de 4096 octets, la page de garde veille sur une plage de mémoire de cette taille. Si un appel de fonction alloue plus de 4096 octets de variables locales, il est possible que le premier accès de la pile s'étende réellement à au-delà de la page de garde. La page suivante peut être supposée être de la mémoire non réservée, donc une violation d'accès aurait du sens dans ce cas.

Bien sûr, vous ne déclarez explicitement aucune variable locale dans votre exemple. Je suppose que l'un des opérateurs < <() méthodes alloue plus d'une page de variables locales. En d'autres termes, que la violation d'accès se produit au début d'un opérateur < <() méthode ou une autre partie de l'implémentation de cout (constructeurs d'objets temporaires, etc.)

Aussi, même dans la fonction que vous avez écrite, le opérateur < <() les implémentations vont avoir besoin de créer du stockage pour les résultats intermédiaires. Ce stockage est probablement alloué en tant que stockage local par le compilateur. Je doute que cela puisse ajouter jusqu'à 4k dans votre exemple, cependant. La seule façon de vraiment comprendre serait de voir une trace de pile de la violation d'accès pour voir quelle instruction la déclenche.Vous avez une trace de pile de la violation d'accès et un désassemblage autour de la zone de l'opcode fautif?

Si vous utilisez le compilateur Microsoft C, une autre possibilité est que printf() et votre propre fonction ont été compilés avec/Ge et l'opérateur < <() ne l'était pas, ou que seule votre fonction a été compilée avec/Ge et ses facteurs semblables à ceux décrits ci-dessus provoquent par hasard le comportement que vous voyez - parce que dans l'exemple printf() l'accident se produit pendant que votre fonction est appelée et dans l'opérateur < <() cas pendant que vous appelez la bibliothèque.

+0

@Heath, "pourquoi l'exemple de cout ne plante pas avec" Stack Overflow "aussi?" : OUI :). Réponse fantastique – mahesh

+0

Merci mahesh. Veuillez noter également qu'une explication similaire s'appliquerait si vous utilisez le commutateur Microsoft/Ge, comme je l'ai ajouté ci-dessus. –

+0

Heath, Yeha ... Merci beaucoup pour ça :). – mahesh

4

Les deux fonctions récursives ne seront jamais arrêter. Il semble que dans le second cas, aucune optimisation de queue n'est faite par le compilateur, donc le débordement de pile.

1

L'appel récursif infini concerne le dépassement de capacité de la pile. Quant à la violation d'accès ... cela dépend vraiment de l'implémentation des flux STL. Vous devez jeter un oeil sur le code source des flux pour savoir ...

0

Bien que la plupart des gens aient mal compris votre question, la réponse est là.

Le deuxième exemple se termine par un débordement de pile car chaque appel de fonction pousse une image sur la pile. Finalement, ça devient trop gros. Je suis d'accord avec Cătălin Pitiş, qu'il serait difficile de savoir pourquoi l'exemple de flux se termine par une violation d'accès sans regarder la source.

+1

Y a-t-il une différence entre cette réponse et celle de Cătălin Pitiş? – SadSido

2

Les deux fonctions déclenchent un débordement de pile sur ma machine. Je compile avec MS Visual Studio 2005. Peut-être vous devez spécifier votre compilateur & de la plate-forme, qui aidera à enquêter ...

Peut-être que vous compilez quelque chose dans le mode de débogage et votre "cout" implémentation comprend quelques contrôles, que ne peut pas être effectuée en raison de la corruption de la pile? Peut-être votre compilateur a-t-il généré le code, qui essaie de récupérer à partir du débordement de la pile et fait apparaître une adresse de retour invalide? Peut-être que vous l'exécutez sur l'appareil mobile? Difficile à dire sans connaître la plateforme et le compilateur.

0

cela me rappelle du problème de la pile étant corrompu et le débogueur ne pas attraper le programme ne s'écraser

Questions connexes