티스토리 뷰



C언어로 프로그램을 개발하면서 오류를 찾다가 의외의 장소에서 문제를 찾는 경우가 몇번 있었는데 바로 매크로 입니다. C언어에서는 "#define 매크로이름 매크로내용"의 형식으로 매크로를 정의하는데 이 매크로는 실행 과정에 영향을 미치는 것이 아니라 컴파일 과정에만 영향을 미칩니다. 컴파일러가 C 소스 코드를 본격적으로 컴파일하기에 앞서 전처리 과정을(precompile) 거치는데 이때 다루어지는 것이 #define문을 사용하는 매크로입니다. C언어에서는 #define 말고도 #include, #ifdef등의 전처리 문장이 있습니다.

2015년 정보 올림피아드 예선에서도 이 매크로를 다루었습니다.


위의 문제에서는 sq(x)라는 매크로를 정의했는데 이 매크로는 프로그램 실행 과정에 동작하는 것이 아니고 컴파일 시점에 소스 코드를 변경하는데 영향을 미침을 다시한번 말씀드립니다. 컴파일러가 sq(x)와 같은 매크로를 만나면 매크로를 호출할 때 전달한 인수를 대입하여 매크로 내용을 기존 소스에 대치시키는 단순한 작업만을 수행합니다. 위의 코드에 대한 전처리 작업을 거친 코드는 아래와 같습니다.

int main() {
    int z = 4;
    printf("%d %d\n", z*z, z+1*z+1);
    return 0;
}

x 대신 "z"와 "z+1"을 적용하여 "z*z"과 "z+1*z+1"로 대치시킨 것이지요. 매크로를 잘 이해하고 있지 않다면 이 문제에 있는 함정을 그냥 지난 칠 수 있습니다. printf의 첫번째 출력값은 4*4=16으로 별 문제가 없지만 두번째 출력을 4+1을 곱한것으로 생각하여 5*5=25로 하면 바로 함정에 빠지는 것입니다. 앞에서 강조했듯이 C언어의 매크로가 동작하는 시점은 실행 과정이 아니라 전처리 과정으로 실행 과정에서는 "z+1*z+1"를 계산해야 합니다. 그러나, 문장을 보시면 아시겠지만 중간에 곱셈이 있으므로 연산 우선 순위에 따라 곱셈을 먼저 하므로 결과는 4+4+1=9입니다. 정답은 2번 "16 9"인 것이지요.

만약 매크로를 "#define sq(x) (x*x)"로 정의 했다면 결과는 일반 함수를 호출한것과 같은 결과로 "(4)*(4)" 와 "(4+1)*(4+1)"의 "16 25"가 되는 것입니다. C언어는 문장 끝에 세미콜론(;)을 붙여야 하므로 매크로 정의 문장에도 세미콜론을 붙이는 실수를 하는 경우가 많은데 이렇게 매크로 속에 들어간 세미콜론 조차도 전처리 과정에서 소스 코드에 그대로 대치되기 때문에 이상한 코드 흐름이 되거나 문법 오류(Syntax error)를 발생시킬 수 있습니다. 그러므로 매크로 사용을 매우 주의해야 하고 최근에는 매크로를 사용하지 않도록 강제하는 조직도 있습니다. 위의 문제 처럼 도통 잡을 수 없는 문제를 발생시킬수 있기 때문인 것이죠.

매크로를 통해서 소스 코드가 간단하고 깔끔하게 보이게 할 수는 있지만 오류의 가능성도 높음을 꼭 기억하세요.



댓글
댓글쓰기 폼