LOG 출력 함수

: 프로젝트의 크기가 제법 되는 경우에는 개발과 추후 디버깅을 위해서 로그를 사용하는 일이 많다. 그렇지 않다면 개발 시 일일히 print 함수를 찍어보며 값을 확인하거나 GDB 툴을 이용해야만 한다. GDB를 이용하는 방법은 괜찮지만 printf 함수를 이용해 값을 일일히 찍어보는 것은 여간 귀찮은 일이 아닐 수 없다. 이러한 필요성에 따라 로그 함수를 작성하는 방법에 대해 알아보자.

자체 LOG 출력 함수 만들기

: 다음과 같이 LOG 출력 함수를 만들 수 있다.

#include <stdio.h>
#include <stdarg.h>

#define LOG(fmt, ...) print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)

void print_log(const char *file, const char *func, int line, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);

    printf("%s/%s(%d): ", file, func, line);
    printf(fmt, ap);

    va_end(ap);

    printf("\\n");
}
int main() {
    LOG("Hello");

    return 0;
}

그리고 그 실행결과는 다음과 같다.

jay@ ~/Desktop/tutorial/log $ ./main 
main.cc/main(17): Hello

Inside LOG 출력 함수

: 위의 LOG 출력 함수에 사용된 여러가지 사항들에 대해 알아보자.

  1. #define LOG(fmt, ...)... 이 가지는 의미
    • ...variadic function을 정의할 때 사용되는데, 이는 가변 갯수의 parameter가 들어올 수 있음을 의미한다.
    • 대표적인 variadic function이 printf로, printf("%d \\n", 1), printf("%d %d \\n", 1, 2)와 같이 함수의 parameter가 정해져 있지 않다.
  2. print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)__FILE__, __FUNCTION__, __LINE__ 이 가지는 의미
    • FILE과 같이 두 개의 연속된 underscore로 시작하는 변수들은 대부분 컴파일러에 pre-define 되어있는 값들이다.
    • 여기서 FILE은 해당 명령어가 호출되고 있는 파일의 이름, FUNCTION은 해당 명령어가 속해있는 함수의 이름, LINE은 해당 명령어가 해당 파일의 몇 번째 라인에 위치해 있는지를 나타낸다.
  3. print_log(__FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__)##__VA_ARGS__가 가지는 의미
    • __VA_ARGS는 앞의 define 문에서의 ...에 대치되는 문구이다.
    • 여기서 ##이 붙은 이유는, LOG("Hi %s", "Jay")가 아닌 LOG("Hi")를 호출하였을 때 ...에 해당하는 argument가 없기 때문에 컴파일 오류가 나는 것을 방지하기 위함이다.
  4. va_list, va_start, va_end 이란?
    • 위의 variadic function에서 parameter의 갯수는 제한이 없다. 따라서 parameter에 어떤 값들이 들어오는지는 미정인 상태이므로, parameter에 들어오는 값들을 순회하여야 할 필요가 있다.
    • 따라서 va_start를 이용해 순회하고자 하는 파라미터의 위치를 지정하고, va_start, va_end로 각각 순회 리스트를 생성, 종료시킨다.

+ Recent posts