메아리

Tour de IOCCC: 1994/smr

이 코드는 도대체 뭘까요? (힌트: 저는 실수하지 않았습니다.)

뭘 하는 프로그램인가?

이 프로그램은 세상에서 가장 작은 자기 복제 프로그램(자기 자신을 출력하는 프로그램)입니다. 이 프로그램보다 더 작은 건 없습니다. 0바이트거든요.

이 프로그램의 실행 과정은 당시 함께 배포된 Makefile로만 설명할 수 있습니다.

$ make smr
$ ./smr
$

물론 출력하는 게 없으니 자기 자신을 출력하는 셈이 됩니다.

왜 동작하는가?

이 프로그램은 일단 올바른 C 프로그램이 아닙니다. ISO/IEC 9899:1999(C99 표준)에 따르면 하나의 번역 단위(translation unit; 일반적으로 전처리기를 거친 소스 코드)는 하나 이상의 선언을 가져야 하기 때문입니다. 흥미로운 점은 전처리기에는 빈 파일이 들어 갈 수 있다는 것인데, 뭐 이런 차이는 그러려니 합시다.

올바른 C 프로그램이 아닌데다가 main 함수도 없으니 웬만해서는 컴파일이 될 리가 없습니다. 힌트 파일에는 일부 컴파일러들에서는 컴파일이 된다고 했지만 그 때는 그 때고 지금은 지금이죠. 하지만 저자가 "보장됨"(Guaranteed)이라는 말까지 써 가면서 당당하게 주장했던 것은 Makefile 때문입니다.

실제 Makefile에는 이렇게 쓰여 있습니다.

smr: smr.c
    @${RM} -rf smr
    ${CP} smr.c smr
    ${CHMOD} +x smr

유닉스에 익숙하지 않은 사람을 위해 한 줄씩 설명하면,

따라서 이 Makefile은 "빈 실행파일"을 만들어서 문제를 해결한 것입니다. 위에서 봤듯이 빈 실행파일은 아무 문제 없이 잘 실행됩니다.

유닉스에서 실행 가능한(+x 퍼미션이 붙은) 파일은 보통 두 종류로 나뉩니다. 하나는 진짜 바이너리 파일로 ELF나 a.out과 같은 전용 포맷으로 되어 있으며 당연히 빈 파일이 될 수 없습니다. 다른 하나는 다른 지정된 프로그램을 통해 실행되도록 한 파일로 흔히 셸 스크립트나 스크립팅 언어로 된 프로그램이 여기에 속합니다. 이런 프로그램은 보통 다음과 같이 맨 앞에 #!로 시작하는 줄로 어떤 프로그램이 필요한지 지정하곤 합니다.

#!/bin/cat
사실 이 파일도 실행 파일만 붙이면 프로그램입니다!
(cat는 지정된 파일의 내용을 보여 주는 유닉스 명령어입니다.)

하지만 #!가 없는 경우에도 운영체제는 해당 파일을 셸 스크립트로 처리하도록 되어 있습니다. 이 동작은 POSIX의 exec 함수가 그렇게 동작하도록 되어 있기 때문인데, 빈 파일은 단순히 빈 셸 스크립트이기 때문에 실행이 가능한 것입니다.

이 프로그램은 사실 C보다는 유닉스의 어두운 구석을 찌르긴 했지만, 여하튼 심사위원들은 이 프로그램에 Worst Abuse of the Rules라는 이름의 상을 주었습니다. (소스 코드 크기에 최소 크기 제한은 없었으니) 그리고 다음 해 대회 가이드라인에서는 다음과 같은 내용을 볼 수 있었습니다...

We suggest that you avoid trying for the 'smallest self-replicating' source. The smallest, a zero byte entry, won in 1994.


Copyright © 1999–2009, Kang Seonghoon.