Q 10.27
__FILE__과 __LINE__ 매크로를, 디버그용으로, 메시지 출력하는 매크로에
쓰고 싶습니다. 어떻게 하면 될까요?
Answer 질문 10.26을 간단히 하기 위해, 따로 만든 질문입니다. 한가지 방법은, 가
변 인자를 받는 함수를 만들고 (질문 15.4, 15.5 참고), __FILE__과 __LINE__
을 받아서 그 함수에 전달해 주는 함수를 따로 만듭니다. 예를 들면:
#include <stdio.h>
#include <stdarg.h>
void debug(char *fmt, ...);
void dbginfo(int, char *);
#define DEBUG dbginfo(__LINE__, __FILE__), debug
static char *dbgfile;
static int dbgline;
void dbginfo(int line, char *file)
{
dbgfile = file;
dbgline = line;
}
void debug(char *fmt, ...)
{
va_list argp;
fprintf(stderr, "DEBUG: \"%s\", line %d: ",
dbgfile, dbgline);
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "\n");
}
이렇게 만들어 두고, 다음과 같이 부르면:
DEBUG("i is %d", i);
다음과 같이 확장됩니다:
dbginfo(__LINE__, __FILE__), debug("i is %d", i);
그리고 아래 문장을 출력합니다:
DEBUG: "x.c", line 10: i is 42
영리한 사람이면 다음과 같이 위 코드를 개선할 수 있습니다:
void debug(char *fmt, ...);
void (*dbginfo(int, char *))(char *, ...);
#define DEBUG (*dbginfo(__LINE__, __FILE__))
void (*dbginfo(int line, char *file))(char *, ...)
{
dbgfile = file;
dbgline = line;
return debug;
}
이 정의에 따라서 DEBUG("i is %d", i);는 다음과 같이 확장됩니다:
(*dbginfo(__LINE__, __FILE__))("i is %d", i);
또 다른, 그리고 간단한 방법으로 아래처럼 만들 수 있습니다:
#define DEBUG printf("DEBUG: \"%s\", line %d: ", \
__FILE__, __LINE__), printf
그러면, DEBUG("i is %d", i);는 다음과 같이 확장됩니다:
printf("DEBUG: \"%s\", line %d: ",
__FILE__, __LINE__), printf("i is %d", i);
Note 다행스럽게도, C99에서 가변 인자를 받을 수 있는 매크로를 지원하기 때문
에 (질문 10.26 참고), DEBUG() 매크로를 다음과 같이 만들 수 있습니다.
#define DEBUG(...) debug(__FILE__, __LINE__, __VA_ARGS__)
void debug(const char *file, int line,
const char *fmt, ...)
{
va_list argp;
fprintf(stderr, "DEBUG: \"%s\", line %d: ",
file, line);
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "\n");
}
위 매크로에 따르면, DEBUG("i is %d", i);는 다음과 같이 확장됩니다:
debug(__FILE__, __LINE__, "i is %d", i);
C99에서는 미리 정의된(predefined) identifier인 __func__를 제공합니다.
(이 것은 __FILE__, __LINE__과는 달리 미리 정의된 매크로가 아닙니다.
자세한 것은 ???를 참고하기 바랍니다.) __func__는 현재 함수의 이름을
가지고 있는 문자열 상수라고 생각하시면 됩니다. 따라서 위 매크로와 함수
를 다음과 같이 만들면 더욱 좋습니다:
#define DEBUG(...) debug(__FILE__, __LINE__, __func__, \
__VA_ARGS__)
void debug(const char *file, int line, const char *func,
const char *fmt, ...)
{
va_list argp;
fprintf(stderr,
"DEBUG: \"%s\", line %d, function \"%s\": ",
file, line, func);
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
fprintf(stderr, "\n");
}
위 매크로에 따르면, DEBUG("i is %d", i);는 다음과 같이 확장됩니다:
debug(__FILE__, __LINE__, __func__, "i is %d", i);