∇ 프로그래밍 소품 및 팁

 ▼ 도움안되는 C 표준 문법

C++

N/A

나는 회사의 코드를 짤 때, 그 일에 재미를 불어 넣기 위해서 여러 가지 장난(?)을 치곤 한다. 예를 들면, NULL로 지정한 class instance를 통해서 class 멤버를 호출하는 방법을 쓴다거나(조건만 맞으면 충분히 가능하다.) 가장 중요한 변수 이름은 smgal로 쓴다거나 exception 발생시 roll-back용 goto 문에는 일본어 의미로 된 label을 쓰다거나 아무도 보지 않을 깊숙한 코드는 macro로 함수 확장을 한다거나(가독성은 현저히 떨어지지만 개발 속도는 빨라짐)하는 방법을 통해 아주 소극적인 방법의 즐거움을 얻곤한다.

어떻게 해서 알게되었는지는 모르겠지만 내가 종종 코드에 집어 넣는 장난 중에 하나가 다음과 같은 것이다. 이 예제에서는 더욱 더 헷갈리게 하기 위해서 극단적으로 코드를 만들어 보았다.

    01: smgal@smgal> gcc --version
    02: gcc (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
    03: Copyright (C) 2004 Free Software Foundation, Inc.
    04: This is free software; see the source for copying conditions.
    05: There is NO warranty; not even for MERCHANTABILITY or FITNESS
    06: FOR A PARTICULAR PURPOSE.
    07:
    08:
    09: smgal@smgal> cat weird.c
    10:
    11: #include <stdio.h>
    12:
    13: int main()
    14: {
    15:         int _[] = {1}, o=0;
    16:         printf("%d\n", _<:o]^o^o^o^o);
    17:
    18:         return 0;
    19: }
    20:
    21:
    22: smgal@smgal> gcc weird.c -o weird.exe
    23:
    24: smgal@smgal> ./weird.exe
    25: 1
    26:
    27: smgal@smgal> gcc weird.c -std=c89
    28: weird.c: In function `main':
    29: weird.c:7: error: parse error before ':' token

위의 리스트는 linux(실제로는 cygwin이지만)의 콘솔에 나타난 출력을 나타낸 것이다.

01~06: 테스트 하려는 gcc의 버전을 확인한다. 3.4.4이다.

09~18: 테스트하려는 c 파일의 내용을 확인한다. (cpp로 해도 동일하다) 일단 주목해야 할 곳은 16번째 줄이다. 마치 이모티콘과 같은 것이 printf의 두 번 째 파라미터로 붙어 있다는 것이 내가 말하고자 하는 도움 안되는 문법을 응용한 것이다.

22: gcc를 통해 문제의 파일을 컴파일 해본다. 그런데 아무런 에러 없이 빌드가 되었다.

24~25: 실행을 시켜 보면 그 결과 값도 출력되고 있다.

문제가 되는 _<:o]^o^o^o^o를 빌드할 수 있는 이유는, 이 선언이 C99에서는 전혀 문제가 되지 않는 문법이기 때문이다. '_'는 변수 이름으로 가능한 문자이며 15번 째 줄에서 배열의 이름으로 선언했기 때문에 문제가 없는 것이고, '^o'의 경우에도 xor를 뜻하는 '^'와 변수 'o'의 조합이기 때문에 아무런 하자가 없다. 그러면 남는 것은 '<:o]'이다. 위치 상으로는 배열에 접근하기 위해 인덱스를 넣는 부분이 와야한다. 그런데 이것은 흔히 보던 것과는 다르다. 일단 답부터 이야기 하자면 C99부터는 '<:'는 '['와 동일하고 ':>'는 ']'와 동일하기 때문이다. 따라서 '[o]' == '<:o:>' == '<:o]'가 된다.

그렇다면 이 c파일을 ANSI-C로 빌드하면 어떻게 될까. 27~29가 그것을 실험한 결과이다. 역시 예상대로 에러가 발생했다.

이 실험을 linux로 보여준 것은 gcc가 C99를 제대로 지원하고 있기 때문이며 VC++ 6.0은 C99를 지원하고 있지 않기 때문에 무조건 에러로만 처리된다. (옵션이 있는지는 잘 모르겠다) 왜 이런 것도 C 표준에 허용하게 되었는지 그 배경은 알지 못한다. 그냥 가독성에 혼란만 주는 것이 아닌가 생각되기도 하는데, 그래도 훌륭하신 분들이 체택하신 것이니 만큼 뭔가 심오한 뜻이 있지는 않을까 생각된다.