Le code suivant ne contient aucune boucle, ni goto
, ni récursivité; pourtant il imprime de 1 à 10 dans la console.
#include <stdio.h> int n = 1; void foo() { int x; printf("%d ", n); if (++n>10) return; *(&x+4) -= 5; } int main() { foo(); return 0; }
Ce code mystérieux * (& x + 4) - = 5;
est à l'origine de la boucle. p >
Autant que j'ai compris - la valeur de x
est conservée dans la mémoire de la pile. Ainsi peut-être, avant que (& x + 4)
il y a le pointeur de la fonction foo
, et foo
est appelé récursivement. p>
Là encore, je ne suis pas sûr que mes hypothèses soient exactes. Je ne comprends pas non plus d'où vient ce 5
. J'ai essayé d'imprimer et d'analyser les adresses (conseillées par mon collègue) du pointeur de fonction et des variables; et associez-les à ma connaissance de la disposition de la mémoire C . Mais je suis devenu plus confus.
S'il y avait plus de variables déclarées avant et après x
, comment * (& x + 4) - = 5; code> changerait?
OS: Windows-7 64 bits, Compilateur: GNU GCC, Editeur: strong > CodeBlocks 16.01
3 Réponses :
Le comportement de * (& x + 4) - = 5;
n'est pas défini car il écrit en dehors des limites de tout objet alloué par le programme. Ce que cela fera dépendra de ce qui sera stocké à cette adresse, le cas échéant. Donc, la réponse courte à la raison pour laquelle votre code se comporte si étrangement est que le code a un bogue qui rend son comportement imprévisible.
Ce qui se passe probablement sur votre plate-forme, c'est qu'elle finit probablement par modifier l'adresse à laquelle elle revient, la faisant revenir à main
avant l'appel à foo
résultant en main
appelant à nouveau foo
.
Ce n'est pas parce que le code n'est pas valide en C ou C ++ qu'il est nécessairement bogué. S'il est livré avec des instructions qu'il est destiné à être compilé avec une version spécifique de GCC pour Windows 7, cela dépend du comportement du compilateur. Ce n'est peut-être même pas un comportement non documenté.
Je n'ai jamais vu de document de compilateur quelque chose comme ça. S'il repose sur un comportement non documenté, c'est bogué. Il n'y a aucun moyen de savoir dans quelles conditions le comportement se produira ou ne se produira pas.
David a raison. Lorsqu'un code essaie d'écrire ou même d'accéder à quelque chose dans le bloc mémoire qui ne lui est pas alloué, il peut faire n'importe quoi (même une explosion nucléaire s'il y a, disons, l'adresse d'une fonction qui fait chier avec le réacteur). Il est de votre responsabilité de prendre en charge les allocations de mémoire car C n'est pas un langage fortement typé. C'est juste une co-incidence qui provoque une boucle. Sur mon système, cela fonctionne comme prévu.
Vous modifiez la pile dans * (& x + 4) - = 5;
C'est un comportement indéfini, et sous un comportement non défini, tout est permis, même pour faire voler des démons hors de votre nez . Voir http://catb.org/jargon/html/N/nasal-demons .html
Peut-être que pour un HW spécifique avec un compilateur spécifique, vous obtenez toujours le même comportement, mais ce n'est pas nécessaire.
Il imprime uniquement
1
puis quitte.Cela dépend d'un comportement non défini. Vous n'êtes pas censé déréférencer une mémoire à
(& x + 4)
lorsquex
est simplementint x
.@Deanie J'ai utilisé le compilateur gcc. Imprime 1 à 10 en C et C ++.
@TheDeepThinker J'ai utilisé le compilateur gcc. Imprime 1 avec un espace, puis sort.
@SouravGhosh J'ai trouvé le code en ligne. Je sais, je ne devrais pas coder comme ça. Je veux simplement connaître l ' explication .
Code auto-modifiable reposant sur la disposition de la pile et les détails de l'architecture matérielle. Cette question est inutile sans ces détails fournis. Par ex. sur mon Fedora 29 x86_64 avec gcc 8.2.1 je n'obtiens qu'un défaut de segmentation. Pas de surprise là-bas, pour être honnête ...
@StefanBecker Ce n'est pas du "code auto-modifiable", c'est juste corrompre sa propre pile.
@duskwuff Merci pour votre commentaire. Pourriez-vous s'il vous plaît dire comment la pile est corrompue.
@duskwuff dans mon livre modifier l'adresse de retour sur la pile est un code auto-modifiable.
@StefanBecker Dans mon livre, ce n'est que du "code auto-modificateur" s'il s'agit de code modificateur . La pile est constituée de données, pas de code.