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 ?
Réponses
Trop de publicités?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).
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).