#ifdef DEBUG 사용하는데 있어서요...

은영신랑의 이미지

대략 다음과 같이 coding 하였습니다.

#ifdef DEBUG
#define DPRINTF(x) fprintf(stderr, "%d : "x, __LINE__)
#else
#define DPRINTF(x)
#endif

int main()
{
int a;
...

DPRINTF(" a : %d\", a);

..
}

제 목적은 디버그모드로 컴파일 하면 Line Number : a : ?
이런식으로 하려는데요,
위 소스를 컴파일하면 DPRINTF passed 2 arguments, but takes just 1
이라는 에러가 나오네요..

도움좀 부탁합니다.

june8th의 이미지

-E 는 preprocess한 다음 멈춥니다.
define이 실제 어떻게 변경되는지 알수 있지요

ihavnoid의 이미지

은영신랑 wrote:
대략 다음과 같이 coding 하였습니다.

#ifdef DEBUG
#define DPRINTF(x) fprintf(stderr, "%d : "x, __LINE__)
#else
#define DPRINTF(x)
#endif

int main()
{
int a;
...

DPRINTF(" a : %d\", a);

..
}

제 목적은 디버그모드로 컴파일 하면 Line Number : a : ?
이런식으로 하려는데요,
위 소스를 컴파일하면 DPRINTF passed 2 arguments, but takes just 1
이라는 에러가 나오네요..

도움좀 부탁합니다.

원하시는 대로 하려면 이게 아닐가 싶은데요....

#define DPRINTF(msg, args...) fprintf(stderr, "%d : " msg, __LINE__, ## args)

제가 #define문의 정확한 규칙을 아는 건 아니지만....
리눅스 커널소스에서 부린 꽁수를 참고했습니다....

http://lxr.linux.no/source/include/linux/sunrpc/debug.h

Consider the ravens: for they neither sow nor reap; which neither have storehouse nor barn; and God feedeth them: how much more are ye better than the fowls?
Luke 12:24

maddog의 이미지

msvc++에서는 매크로에서는 varg를 사용할 수가 없어서
저는 주로 함수명을 사용한 트릭(?)을 사용합니다.

-- debug.h
...
#ifdef DEBUG
#define DPRINTF debug_printf
#else
#define DPRINTF dummy_printf
#endif 


int debug_printf( const char *format, ... ) ;
inline int dummy_printf( const char *format, ... ) 
{
  return 0 ;
}
...

dummy_printf는 아무짓도 안하고 그냥 리턴하는 함수가 되겠구요,
debug_printf는 뭐 적당히 필요한 짓 하게 되겠죠. 그럴바에야 그냥
debug_printf를 수정하지... 하시는 분도 있지만 저런 경우가 종종
필요하니까요. 그리고 dummy_printf 같은 넘은 인라인으로 처리해서
함수 호출에 따른 오버헤드는 제거될 수도 있는 문제구요...

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
재미없는 일은 하지 않겠다는 인간 쓰레기. ㅡ,.ㅡ;;
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

seed의 이미지

위코드에서는 이한줄만 바꾸면 되지 않을까하는...

#define DPRINTF(x,y) fprintf(stderr, "%d : "x,y, __LINE__)

cinsk의 이미지

아래 코드를 보시면 알겠지만 쓰는 법은 어렵지 않습니다.
(그리고 아직 test는 안해봤지만, VC++에서도 돌아갈 겁니다.)

또한 표준 C (ISO C)에 어긋나지도 않습니다.

일단, <assert.h>와 일관성을 유지하기 위해서, NDEBUG란 매크로를 씁니다. 즉, 여러분의 소스 코드에서 #include "debugmsg.h"를 하기 전에 NDEBUG란 매크로를 정의하면 DEBUG_MSG는 아무런 일도 하지 않습니다.

그리고 DEBUG_MSG는 printf와 정확히 같은 일을 하며, 대신 호출한 파일 이름과 줄 번호를 먼저 출력합니다. 그리고 디폴트로 메시지는 stderr로 나가며, 이것을 고치고 싶으면, 다른 스트림을 debug_stream_에 대입하면 됩니다.

NDEBUG를 정의하면 DEBUG_MSG를 쓰는 overhead는 단지 FILE *타입의 전역 변수 debug_stream_이 있다는 것 뿐입니다. 그럼 이만.

아래는 debugmsg.h입니다.

#ifndef __DEBUGMSG_H
#define __DEBUGMSG_H

extern FILE *debug_stream_;

#ifdef NDEBUG
#define DEBUG_MSG(...)	((void)0)
#else

#include <stdio.h>

extern void _debug_printf_(const char *filename, int lineno, 
                           const char *fmt, ...);

#define DEBUG_MSG(...)	_debug_printf_(__FILE__, __LINE__, __VA_ARG__)
#endif /* NDEBUG */

#endif /* __DEBUGMSG_H */

아래는 debugmsg.c입니다.

#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "debugmsg.h"

FILE *debug_stream_ = stderr;

#define DEBUG_LINE_MAX	1024

void
_debug_printf_(const char *filename, int lineno, const char *fmt, ...)
{
  va_list argptr;
  char sbuf[DEBUG_LINE_MAX];

  fprintf(debug_stream_, "%s:%s: ", filename, lineno);

  va_start(argptr, fmt);
  vfprintf(debug_stream_, fmt, argptr);
  va_end(argptr);

  fputc('\n', debug_stream_);

  fflush(debug_stream_);
}
purewell의 이미지

#ifndef NDEBUG
#define DEBUGMSG(msg...) {fprintf(strerr, msg);fprintf(stderr, "\n");}
#else
#define DEBUGMSG(msg...)
#endif

이렇게 정의하고

int main(int,char*[])
{
  DEBUGMSG("Line: %d", __LINE__);
  return 0;
}

이렇게 쓰시면 됩니다.

디버그 기능을 끄려면 컴파일러 옵션에 -DNDEBUG 을 추가하면

됩니다.

_____________________________
언제나 맑고픈 샘이가...
http://purewell.biz

송지석의 이미지

#ifdef DEBUG
#define DMSG( msgs...) do {\
    fprintf(DEBUG_MESSAGE_FILE, "%s:%4d: %s(): ",  __FILE__, __LINE__, __FUNCTION__);\
    fprintf(DEBUG_MESSAGE_FILE, msgs);\
} while(0)

#define DMSG_SHORT( msgs...) do {\
    fprintf(DEBUG_MESSAGE_FILE, "%s(): ", __FUNCTION__);\
    fprintf(DEBUG_MESSAGE_FILE, msgs);\
} while(0)

#define DMSG_ERR( msg) do {\
    fprintf(DEBUG_MESSAGE_FILE, "%s(): ", __FUNCTION__);\
    perror(msg);\
} while(0)

#else

#define DMSG(msgs...) {}
#define DMSG_SHORT(msgs...) {}
#define DMSG_ERR(msgs...) {}

이런식으로 하시면 되지 않을까요? DEBUG_MESSAGE_FILE에 따라서 stdout이나 stderr또는 일반 파일에 쓰실 수 있고요.

#ifdef DEBUG
#define DMSG(n, msgs...) do {\
    if( (n) & DEBUG_MASK ) {\
        fprintf(DEBUG_MESSAGE_FILE, "[%02x]%s:%4d: %s(): ", n, __FILE__, __LINE__, __FUNCTION__);\
        fprintf(DEBUG_MESSAGE_FILE, msgs);\
    }\
} while(0)

#define DMSG_SHORT(n, msgs...) do {\
    if( (n) & DEBUG_MASK ) {\
        fprintf(DEBUG_MESSAGE_FILE, "%s(): ", __FUNCTION__);\
        fprintf(DEBUG_MESSAGE_FILE, msgs);\
    }\
} while(0)

#define DMSG_ERR(n, msg) do {\
    if( (n) & DEBUG_MASK ) {\
        fprintf(DEBUG_MESSAGE_FILE, "%s(): ", __FUNCTION__);\
        perror(msg);\
    }\
} while(0)

#else

#define DMSG(n, msgs...) {}
#define DMSG_SHORT(n, msgs...) {}
#define DMSG_ERR(n, msgs...) {}
디베그 레벨에 따라 나오는 메시지를 다르게 하려고 디버그 마스크까지 쓰시면 이런식으로 하시면 될 것 같습니다만...
(요는 msgs뒤에 ...을 붙이면 되에 인자까지 되니까 printf처럼 쓰실 수 있잖아요 :-) )
cinsk의 이미지

다들 이런 분야에 관심이 많으시군요. :D

예 저도 좀 찾아봤는데.

#define eprintf(args...) fprintf (stderr, args)

와 같은 방식은, GNU CPP와 같은 c preprocessor가 제공하는 확장 기능이라고 하군요. 즉 표준 C가 아니라는 것이죠.

표준은, "args..."가 아닌 "..."을 단독으로 쓰고, __VA_ARGS__를 쓰는 것이라는 데, 아직 쓸 만한게 아니라고 합니다. 예를 들어,

#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)

와 같이 했을때, format을 제외하고 아무런 메시지를 전달하지 않을 때, __VA_ARGS__ 바로 앞의 ","가 문제가 되기 때문입니다.

이것을 ISO C에서는 variadic macro라고 하는데, GNU CPP info 문서에 따르면, 표준 자체가 좀 애매하다고 하는군요.

흠.. 제 생각에는 개인 취향이라 할까요? 완벽히 동작하는 가변 인자 매크로를 원하면, 컴파일러가 제공하는 확장 기능을 사용하는 "args..." 형식을 쓰는 것이 좋을 것이고, 불안하더라도 표준에 충실하고 싶으면 "..."와 __VA_ARGS__를 쓰는 것이 좋겠죠.

남성식의 이미지

#define eprintf(format, ...) fprintf (stderr, format, __VA_ARGS__)

#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)

과 같이 하면 불필요한 앞의 쉼표를 삭제합니다.

익명 사용자의 이미지

Here's another trick:

#define BAR_HELPER(fmt, ...) printf(fmt "\n", __VA_ARGS__)
#define BAR(...) BAR_HELPER(__VA_ARGS__, 0)

, referring to http://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick

purewell의 이미지

ㅡ_-);;;

#ifndef NDEBUG
#define DEBUGMSG(x,...)    fprintf(stderr, x, __VA_ARGS__)
#else
#define DEBUGMSG(x,...)
#endif

GCC에서 저 구문이 제대로 돌아가는데
VC6SP5에서는 오류가 나는군요.

ㅡ_-)/ 누가 BCC 5.5 Free Compiler로 테스트 좀 해주세요~

Always wish be pure well...

_____________________________
언제나 맑고픈 샘이가...
http://purewell.biz

aero의 이미지

VC++ 6.0 에서는 __VA_ARGS__ 가 어떤 헤더파일에서도 정의되지 않은것 같더군요.

VC++ 7.0 은 어떤가요?

scwpark의 이미지

#include <stdio.h>

/* :lol:
Define Function만들때 '\' 뒤에 공백이나 tab키가 들어가면 컴파일에러 발생합니다
*/
#include <stdio.h>

#define DPRINTF( __FORMAT__, __ARGS__ ) \
do \
{\
printf( "[Line :%d] ", __LINE__);\
printf(__FORMAT__, __ARGS__);\
printf("\n");\
}while(0)

void main()
{
int ab =1;
DPRINTF( " a : %d \n", ab );

//printf(" a : %s \n", ab);

}

=> 실행결과
[Line : 50] a : 1

vigor96의 이미지

aero wrote:
VC++ 6.0 에서는 __VA_ARGS__ 가 어떤 헤더파일에서도 정의되지 않은것 같더군요.

VC++ 7.0 은 어떤가요?

http://groups.google.co.kr/groups?hl=ko&lr=&ie=UTF-8&oe=UTF-8&newwindow=1&threadm=eTXXYF8uCHA.848%40TK2MSFTNGP11&rnum=3&prev=/groups%3Fhl%3Dko%26lr%3D%26ie%3DUTF-8%26oe%3DUTF-8%26newwindow%3D1%26q%3D__VA_ARGS__%2Bvc

에 보시면 알겠지만요.

Quote:
No, we will not be supporting variadic macros in either 7.1 or in the Yukon
release.

Ronald Laeremans
Visual C++ team

라네요..

vigor96의 이미지

FAQ 10.26 에 있는 내용입니다.

VC++ 에서 쓸 수 있는...

Quote:
How can I write a macro which takes a variable number of arguments?

One popular trick is to define and invoke the macro with a single, parenthesized ``argument'' which in the macro expansion becomes the entire argument list, parentheses and all, for a function such as printf:

#define DEBUG(args) (printf("DEBUG: "), printf args)

if(n != 0) DEBUG(("n is %d\n", n));

The obvious disadvantage is that the caller must always remember to use the extra parentheses.

gcc has an extension which allows a function-like macro to accept a variable number of arguments, but it's not standard. Other possible solutions are to use different macros (DEBUG1, DEBUG2, etc.) depending on the number of arguments, to play games with commas:

#define DEBUG(args) (printf("DEBUG: "), printf(args))
#define _ ,

DEBUG("i = %d" _ i)

It is often better to use a bona-fide function, which can take a variable number of arguments in a well-defined way. See questions 15.4 and 15.5.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.