메아리 저널

C/C++의 escape sequence

object 님 글을 보고 생각나서 씀.

C/C++는 워낙 레거시가 많은 언어라(물론 포트란만 하겠느냐만...) 가끔씩 이해도 안 되는 문제 때문에 고생하고는 한다. escape sequence에 관련해서도 비슷한 것이 있다.

다음 코드는 무엇을 출력할까?

#include <stdio.h>

int main() {
        printf("\x12345\n");
}

정답은 "E"이다. 아니, 엄밀하게는 올바른 C가 아니라 에러가 날 수도 있지만 하여튼 많은 컴파일러가 "E"로 출력하게 컴파일한다. 어떤 경우든 절대로 네 글자를 출력하지 않음은 확실하다. (요컨대 "\x12" "345" 식으로 해석되지 않는다는 것) 여기에 대해서는 부연 설명이 필요하다.

쉽게 설명하면 이렇다. 십육진법 escape sequence는 가능한 많은 자릿수를 읽는다. 팔진법 escape sequence는 세 자리까지만 읽고 끝난다. (그래서 만약 문자열로 바이너리 데이터를 넣는다면 팔진법으로 넣는 게 훨씬 간단하다.)

사람들의 인식과 전혀 동떨어지는 C/C++의 이 동작이 K&R 시절에도 있었는지는 잘 모르겠다. (어쩌면 십육진법 escape sequence 자체가 없었을 지도 모르겠다.) 하여튼 이 동작은 1바이트가 8비트보다 커질 수 있다는 그다지 쓸모 없는 지식에서 출발한다. 아니 바이트를 따지고 들기 전에 wchar_t를 생각하면 얘는 16비트거나 32비트인 경우가 보통이니 L"\xac00" 식으로 쓸 수 있지 않아야 하겠는가?

다행히(?) "\x12345"처럼 한 문자가 자료형에 안 맞는 경우가 발생하면 이 경우는 undefined behavior라 하여 구현체가 뭔 짓을 해도 할 말이 없다. (ISO/IEC 9899:1999 6.4.4.4 #9; "shall"의 정의에 대해서는 section 4 #1/2를 참고) 하지만 웬만한 컴파일러가 이걸 하위 비트만 잘라서 사용하기 때문에(경고 띄우고), "\x45", 즉 "E"와 같은 결과를 내는 것이다.

앞으로 C++0x에 유니코드 문자열이 추가되면 \u#### 식의 escape sequence가 추가될 게 뻔한데 이건 확실히 네 자리로 처리될 것이므로 걱정할 필요는 없다. 하지만 \x를 쓸 때는 언제나 주의해야 함을 잊지 말자.

이 글은 본래 http://arachneng.egloos.com/1364301에 썼던 것을 옮겨 온 것입니다.


(rev 1d46270eb038)