루프 또는 조건부없이 1에서 1000까지 인쇄하는C
코드를 찾았습니다 .하지만 작동 방식을 이해하지 못합니다. 누구나 코드를 살펴보고 각 줄을 설명 할 수 있습니까?
#include <stdio.h>
#include <stdlib.h>
void main(int j) {
printf("%d\n", j);
(&main + (&exit - &main)*(j/1000))(j+1);
}
답변
그런 코드를 작성하지 마십시오.
를 들어 j<1000
, j/1000
영 (정수 나눗셈)이다. 그래서:
(&main + (&exit - &main)*(j/1000))(j+1);
다음과 같습니다.
(&main + (&exit - &main)*0)(j+1);
어느 것이 :
(&main)(j+1);
어느 전화 main
로 j+1
.
인 경우 j == 1000
다음과 같은 줄이 나타납니다.
(&main + (&exit - &main)*1)(j+1);
끓는점
(&exit)(j+1);
어느 것이 exit(j+1)
프로그램을 떠난다.
(&exit)(j+1)
과는 exit(j+1)
본질적으로 같은 것입니다 – C99을 인용 §6.3.2.1 / 4 :
함수 지정자는 함수 유형이있는 표현식입니다. sizeof 연산자 또는 단항 & 연산자 의 피연산자 인 경우를 제외하고 , ” function returning type ” 유형의 함수 지정자는 ” function returning type 에 대한 포인터 “유형의 표현식으로 변환됩니다 .
exit
함수 지정자입니다. 단항 &
주소 연산자가 없어도 함수에 대한 포인터로 취급됩니다. ( &
그냥 명시 적으로 만듭니다.)
함수 호출은 §6.5.2.2 / 1 및 다음에 설명되어 있습니다.
호출 된 함수를 나타내는 표현식은 void를 반환하거나 배열 유형 이외의 객체 유형을 반환하는 함수에 대한 유형 포인터를 가져야 합니다.
따라서 exit(j+1)
함수 유형을 포인터 대 함수 유형으로 자동 변환하기 때문에 작동하며 포인터 대 함수 유형 (&exit)(j+1)
으로의 명시 적 변환과 함께 작동합니다.
즉, 위의 코드는 일치하지 않으며 ( main
두 가지 주장을 취하거나 전혀 고려하지 않음) &exit - &main
§6.5.6 / 9에 따라 정의되지 않았습니다.
두 개의 포인터를 빼면 둘 다 같은 배열 객체의 요소를 가리 키 거나 하나는 배열 객체의 마지막 요소를 지나야합니다. …
추가는 (&main + ...)
그 자체로 유효한 것, 그리고 사용할 수있는 경우 양이 영 (0)이 추가 §6.5.6 / 7 말한다 이후 :
이러한 연산자의 목적 상, 배열의 요소가 아닌 객체에 대한 포인터는 객체 유형을 요소 유형으로하여 길이가 1 인 배열의 첫 번째 요소에 대한 포인터와 동일하게 동작합니다.
따라서 0을 추가하면 &main
괜찮을 것입니다 (그러나 많이 사용하지는 않음).
답변
재귀, 포인터 산술을 사용하고 정수 나누기의 반올림 동작을 이용합니다.
이 j/1000
용어는 모두 0으로 내림합니다 j < 1000
. 일단 j
도달하면 (1000)는 1로 평가.
지금 당신이있는 경우 a + (b - a) * n
, 여기서 n
0 또는 1, 당신은으로 끝날 a
경우 n == 0
, 그리고 b
경우 n == 1
. 사용 &main
(주소 main()
)와 &exit
대한 a
및 b
용어 (&main + (&exit - &main) * (j/1000))
수익률 1000 이하를 , 그렇지. 그런 다음 결과 함수 포인터에 인수가 제공 됩니다.&main
j
&exit
j+1
이 전체 구조는 재귀 동작을 초래 j
합니다. 1000 미만인 동안 main
재귀 적으로 호출됩니다. 때 j
1000에 도달, 그것을 호출 exit
종료 코드 1001로 프로그램 종료하고, 대신 (종류 더러운이지만, 작품).