2013-08-01 6 views
2

다음 프로그램은 자신을 호출하는 C 매크로처럼 보입니다.자체를 호출하는 매크로 자체가 인쇄됩니까?

#define q(k)int puts();int main(){puts(#k"\nq("#k")");} 
q(#define q(k)int puts();int main(){puts(#k"\nq("#k")");}) 

It compiles and runs fine. 그것은 스스로를 인쇄합니다.

이 코드는 실제로 C입니까? 즉, 제대로 작동하려면 표준 C 이외의 다른 것에 의존합니까?

이 프로그램이 제대로 작동하려면 표준 C 이외의 아무것도에 의존 하는가
#define q(k)main(){return!puts(#k"\nq("#k")");} 
q(#define q(k)main(){return!puts(#k"\nq("#k")");}) 

:

@devnull는 this question 비슷한 프로그램을 가지고 있다고 지적했다?

+1

보인다

DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET, QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD]. ENIUQ ['DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET, QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD]. ENIUQ']. 
여담으로

, 여기 역순으로 소스 코드를 출력 프로그램의 버전입니다/questions/8200668/인쇄 할 수있는 짧은 코드로 도울 수 있습니다 – devnull

+0

@devnull : 좀 더 구별되도록 질문을 수정했습니다. 당신이 참조한 것은 실제로 어떤 C 표준에도 부합하지 않습니다. – jxh

+0

아하! 그래서 당신은 이것이 표준에 부합 함을 제안하는 것처럼 보입니다. 그러면 무엇이 같은 질문을합니까? – devnull

답변

7

첫 번째 프로그램은 C로 quine을 구현 한 예입니다. 상위 수준에서 q() 매크로를 정의하여 두 줄을 인쇄하는 main()이라는 정의를 만듭니다. 첫 번째 줄은 그 자체로 인수이고, 두 번째 줄은 q()에 대한 호출에서 줄 바꿈 된 인수입니다.

foo 
q(foo) 

foo 대신 매크로 정의 자체를 대체 : 컴파일 및 실행하면 출력 결과

int puts();int main(){puts("foo""\nq(""foo"")");} 

: 그래서, 다음의 프로그램 :로

#define q(k)int puts();int main(){puts(#k"\nq("#k")");} 
q(foo) 

은 확장 결과가 한 짝짓기. 매크로는 실제로 자신을 호출하지 않으며, 매크로를 정의하는 동일한 텍스트에서 호출됩니다. C에서 매크로는 재귀 적으로 확장되지 않습니다 (C.99 § 6.10.3.4 ¶ 2).

질문에서 언급했듯이이 프로그램은 엄격한 C.99 설정 (-pedantic -std=c99)을 사용하여 GCC에서 불만없이 컴파일됩니다. 이 프로그램은 표준 C 기능 만 사용하며 C.99와 C.11을 모두 준수합니다. 인수 substituion (C.99 § 6.10.3.1) 및 # "stringifying"연산자 (C.99 § 6.10.3.2)와

  • 매크로 여분 (C.99 § 6.10.3).
  • 지정되지 않은 인수 목록을 사용하는 함수 선언 (C.99 § 6.7.5.3 ¶ 14).
  • 문자열 리터럴 연결 (C.99 § 5.1.1.2 ¶ 1).
  • 기본값 main() 반환 값 (C.99 § 5.1.2.2.3 ¶ 1).

특히이 프로그램은 문자의 ASCII 인코딩에 의존하지 않습니다.

프로그램은 C.89-90 컴파일러에서 컴파일되지만,에서 값을 반환하지 않는 동작은 C.89-90에 대해 정의되지 않습니다. puts()로 전화 한 후 return 0;을 추가하여 프로그램을 C.89-90 호환으로 쉽게 수정할 수 있습니다.

두 번째 프로그램에 대해서는 두 번째 프로그램이기도합니다. 그러나 C.89-90, C.99, C.도 아닙니다.11 준수. 이는 puts()에 논리 NOT 연산자에 대한 양수를 반환하여 반환 값이 0이되기 때문입니다. 그러나 C는 성공시에만 puts()이 음수가 아닌 값을 반환하도록 요구합니다 (C.99 § 7.19.7.10 ¶ 3). C.89-90 만 암시 적 함수 선언을 허용합니다 (C.89, § 3.3.2.2). 프로그램은 return!을 제거한 다음 puts() 호출 후에 return 0;을 추가하여 C.89-90을 준수하도록 수정할 수 있습니다.

이러한 프로그램의 구조는 Douglas R. Hofstadter가 작성한 Gödel, Escher, Bach: An Eternal Golden Braid이라는 책에 소개 된 "가상의"언어 인 BlooP에서 quine 프로그램을 구현 한 것에 크게 영향을 받았습니다 (quine이라는 용어를 사용 했음). http://stackoverflow.com 꽤 비슷한

#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");} 
q(#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");})