Jak działa kod C, który drukuje od 1 do 1000 bez pętli lub instrukcji warunkowych?
Znalazłem C
kod, który drukuje od 1 do 1000 bez pętli i warunkow :
Ale nie rozumiem, jak to działa. Czy ktoś może przejrzeć kod i wyjaśnić każdą linijkę?
#include <stdio.h>
#include <stdlib.h>
void main(int j) {
printf("%d\n", j);
(&main + (&exit - &main)*(j/1000))(j+1);
}
2 answers
Nigdy nie pisz takiego kodu.
Dla j<1000
, j/1000
is zero (integer division). Więc:
(&main + (&exit - &main)*(j/1000))(j+1);
Jest równoważne:
(&main + (&exit - &main)*0)(j+1);
Czyli:
(&main)(j+1);
Który wywołuje main
z j+1
.
If j == 1000
, then the same lines comes out as:
(&main + (&exit - &main)*1)(j+1);
Co sprowadza się do
(&exit)(j+1);
Czyli exit(j+1)
i opuszcza program.
(&exit)(j+1)
i exit(j+1)
są zasadniczo tym samym-cytując C99 §6.3.2.1/4:
Wyznacznik funkcji jest wyrażeniem, które ma typ funkcji. Z wyjątkiem sytuacji, gdy jest to operand operatora sizeof lub operatora uniary & , wyznacznik funkcji z type "funkcja zwracająca Typ "jest konwertowana do wyrażenia, które ma typ" wskaźnik do funkcja zwracająca Typ ".
exit
jest oznacznikiem funkcji. Nawet bez operatora uniary &
address-of, Jest on traktowany jako wskaźnik do funkcji. (The &
just makes it wyraźnie.)
I wywołania funkcji są opisane w §6.5.2.2 / 1 i następujące:
Wyrażenie oznaczające wywołaną funkcję mA typ wskaźnik do funkcji zwracający void lub zwracający typ obiektu inny niż typ tablicy.
Więc exit(j+1)
Działa ze względu na automatyczną konwersję typu funkcji do typu wskaźnik-funkcja, a (&exit)(j+1)
działa również z jawną konwersją do typu wskaźnik-funkcja.
Że jednak powyższy kod nie jest spójny (main
przyjmuje dwa argumenty lub żaden w ogóle), a &exit - &main
jest, jak sądzę, niezdefiniowany zgodnie z §6.5.6 / 9:
Gdy dwa wskaźniki są odejmowane, oba wskazują na elementy tego samego obiektu array , lub jeden obok ostatniego elementu obiektu array; ...
Dodanie (&main + ...)
byłoby ważne samo w sobie i może być użyte, jeśli Dodana ilość była równa zeru, ponieważ §6.5.6/7 mówi:
Do celów tych operatorów, wskaźnik do obiektu, który nie jest elementem tablica zachowuje się tak samo jak wskaźnik do pierwszego elementu tablicy o długości 1 z typ obiektu jako jego Typ elementu.
Więc dodanie zera do &main
byłoby ok (ale nie za bardzo użyteczne).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-04 11:27:51
Używa rekurencji, arytmetyki wskaźników i wykorzystuje zaokrąglanie dzielenia liczb całkowitych.
Termin j/1000
zaokrągla się do 0 dla wszystkich j < 1000
; gdy j
osiągnie 1000, ocenia się do 1.
Teraz jeśli masz a + (b - a) * n
, Gdzie n
jest 0 LUB 1, kończy się a
if n == 0
i b
if n == 1
. Używając &main
(adres main()
) i &exit
dla a
i b
, termin (&main + (&exit - &main) * (j/1000))
zwraca &main
, gdy j
jest poniżej 1000, &exit
w przeciwnym razie. Wynikowy wskaźnik funkcji jest następnie podawany argument j+1
.
Cała konstrukcja powoduje zachowanie rekurencyjne: podczas gdy j
jest poniżej 1000, main
wywołuje się rekurencyjnie; gdy j
osiągnie 1000, wywołuje exit
, powodując zakończenie programu z kodem wyjścia 1001 (który jest trochę brudny, ale działa).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 13:41:59