150 votes

Comment fait le C code qui imprime de 1 à 1000 sans boucles ou instructions conditionnelles travaillent ?

J’ai trouvé `` code ce imprime de 1 à 1000 sans boucles ou conditionnels : mais je ne comprends pas comment cela fonctionne. Peut n’importe qui passent par le code et expliquer chaque ligne ?

267voto

Mat Points 104488

Ne jamais écrire du code comme ça.

Pour j<1000, j/1000 est égal à zéro (division entière). Donc:

(&main + (&exit - &main)*(j/1000))(j+1);

est équivalent à:

(&main + (&exit - &main)*0)(j+1);

Qui est:

(&main)(j+1);

Qui demande main avec j+1.

Si j == 1000, alors le même sort que:

(&main + (&exit - &main)*1)(j+1);

Ce qui revient à

(&exit)(j+1);

Qui est - exit(j+1) et quitte le programme.


(&exit)(j+1) et exit(j+1) sont essentiellement la même chose - en citant C99 §6.3.2.1/4:

Une fonction de désignation est une expression qui a la fonction de type. Sauf quand c'est le l'opérande de l'opérateur sizeof ou unaire & de l'opérateur, une fonction de désignation avec "type defonction de retour de type" est converti en une expression qui a le type "pointeur vers la fonction de retour de type".

exit est une fonction de désignation. Même sans le unaire & -adresse de l'opérateur, il est considéré comme un pointeur de fonction. ( & Tout à fait explicite.)

Et les appels de fonction sont décrites dans le §6.5.2.2/1 et suivants:

L'expression qui désigne la fonction appelée est de type pointeur vers la fonction de retour d'annuler ou de renvoyer un objet de type autre que le type tableau.

Donc, exit(j+1) fonctionne en raison de la conversion automatique de la fonction de type d'un pointeur de type de fonction, et (&exit)(j+1) fonctionne aussi bien avec une conversion explicite à un pointeur de type de fonction.

Cela étant dit, le code ci-dessus n'est pas conforme (main prend deux arguments ou rien du tout), et &exit - &main est, je crois, non défini selon le §6.5.6/9:

Lorsque les deux pointeurs sont soustraits, à la fois doit pointer sur le même objet de tableau, ou un passé le dernier élément de l'objet array; ...

Les plus (&main + ...) serait valable en elle-même, et pourrait être utilisé, si la quantité ajoutée est nulle, puisque §6.5.6/7 dit:

Pour l'application de ces opérateurs, un pointeur vers un objet qui n'est pas un élément d'une tableau se comporte comme un pointeur vers le premier élément d'un tableau de longueur avec le type de l'objet comme type d'élément.

Ainsi, l'ajout de zéro à l' &main serait ok (mais pas beaucoup d'utilisation).

41voto

tdammers Points 14202

Il utilise la récursivité, l'arithmétique des pointeurs, et les exploits de l'arrondissement comportement de la division entière.

L' j/1000 terme arrondit à 0 pour tous les j < 1000; une fois que j atteigne 1000, il prend la valeur 1.

Maintenant, si vous avez a + (b - a) * n, où n est 0 ou 1, vous vous retrouvez avec un si n == 0, et b si n == 1. À l'aide de &main (l'adresse de l' main()) et &exit pour a et b, le terme (&main + (&exit - &main) * (j/1000)) retours &main lorsque j est en dessous de 1000, &exit sinon. Le pointeur fonction résultant est ensuite introduit l'argument j+1.

Cette construction entière résultats récursive comportement: alors que j est en dessous de 1000, main appelle récursivement; quand j atteint 1000, il appelle exit au lieu de cela, faire de la sortie du programme avec le code de sortie 1001 (ce qui est un peu sale, mais qui fonctionne).

-6voto

munna Points 27

Je pense que cela pourrait vous aider

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X