극히 개인적이고 극히 대단하지 않은

C 디버깅용 로그 출력할 때, 자동으로 함수이름과 라인번호 출력하기 본문

20년차 개발자

C 디버깅용 로그 출력할 때, 자동으로 함수이름과 라인번호 출력하기

회색싼타 2020. 9. 11. 20:55

귀차니즘의 극을 달리다가 드디어 정리한다.

뭐 그리 중요하거나 대단한 기술은 아니지만, 더 머리가 굳어가기 전에 남겨두는 게 맞을 것 같아서...

 

코드를 작성하고 디버깅을 하다보면, 코드 어디 쯤 실행이 되고 있는 것인지 확인하는 가장 좋은 방법이 로그를 찍어보는 것이다. 그런데, 간혹 다른 사람의 코드를 디버깅하다보면 'return NOK!' 라는 출력이 있어 여기 쯤 문제가 있겠구나 하고 추정을 하게되고 'return NOK!' 라는 문자열을 소스에서 찾아보게 되는데, 'return NOK!' 라는 문자열이 이런 저런 소스에 분산되어 한 200군데에 있다면, 정말 짜증이 나지 않을 수 없다.

 

개인적으로 간단하게 로그의 위치를 확인하기 위해서는 잘 알려진 방법인 __func__와 __LINE__ 매크로를 사용하는 방법을 쓰곤한다. (__func__와 __FUNCTION__의 차이점을 굳이 확인하고자 하는 포스팅이 꽤 있는데, 20년간 코딩을 하면서 그 둘을 굳이 구분해야할 상황을 한 번도 접하지 않았으므로 따지지 말자.)

 

printf ("<%s:%d> return NOK!\n", __func__, __LINE__);

코드 중간중간에 위와 같은 형식으로 출력을 하게되면 같은 출력이더라도 출력이 발생하는 함수명과 라인번호가 함께 출력이 되기 때문에 따라가기가 영 쉽다.

 

그런데, 디버깅의 양이 방대해지거나 조밀하게 로그를 넣어야 하는 경우에는 반복되는 __func__와 __LINE__ 을 입력하는 데에도 상당한 시간을 들이게되고 짜증이 나는 일이 되기도 한다.

 

그래서, 항상 해야지 해야지 하면서도 게을러서 하지 못했던, __func__와 __LINE__ 을 일일히 입력하지 않아도 되도록 함수와 라인정보를 출력하는 라이브러리의 베이스형을 만들고 여기에 그 흔적을 남긴다.

 

아래는 헤더 파일이고 (log.h 정도로 이름지으면 될 듯)

#define     Log(fmt, args...)           LogPrint(__LINE__, __func__, fmt, ## args)
int LogPrint (const int line, const char *func, const char *format, ... );

그리고 라이브러리 소스 파일 (역시 log.c 정도로 이름지으면 될 듯)이다.

int LogPrint (const int line, const char *func, const char *format, ... )
{
    int     charsNo;
    va_list ap;
    time_t  *cur;
    struct  tm *now, rt;
    struct  timeval tv;

    gettimeofday(&tv, NULL);
    cur = (time_t *)&(tv.tv_sec);
    now = localtime_r(cur, &rt);

    printf( "[%02d:%02d:%02d.%03d] | <%s:%d> ", now->tm_hour, now->tm_min, now->tm_sec, (int)(tv.tv_usec/1000), funcline );

    va_start(ap,format);
    charsNo = vprintf(format,ap);
    va_end(ap);

    return charsNo;
}

log.a라는 라이브러리로 만든 후, 임의의 소스에 Log ("블라블라...\n"); 를 호출하면 예쁘게  

 

위와 같이 출력이 된다.

 

위의 예시에서는 시간정보도 같이 출력하도록 했는데, 소스를 수정하여 시간정보까지 필요없다면 빼버리거나, 파일명 정보(__FILE__ 매크로 이용)를 추가하는 등의 변형도 얼마든지 가능.

 

한번 쯤 아래와 같이 바로 Log 함수를 코딩했다가 낙심한 경험이 있는 개발자들에게 도움이 되기를...

printf( "[%02d:%02d:%02d.%03d] | <%s:%d> ", now->tm_hour, now->tm_min, now->tm_sec, (int)(tv.tv_usec/1000), __func__, __LINE__ ); 

 

Comments