· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
xassert

아직 완전하지 않은 내용입니다. 수정하기 전에 CCodeSnippets를 읽어 주시기 바랍니다. -- cinsk

Interface

Synopsis

#include <xassert.h>

void xassert(scalar expression, const char *format, ...);

Description

만약 <xassert.h>를 포함할 때, NDEBUG 매크로가 정의되어 있으면 xassert()는 아무런 일을 하지 않으며, NDEBUG가 정의되어 있지 않으면, printf(3) 스타일의 메시지를 출력할 수 있다는 것을 제외하고, assert(3)와 똑같이 동작한다.

Note

ISO C를 지원하는 시스템에서 쓸 수 있다. 정확히 말하면, 매크로 VA_ARGS를 지원하는 컴파일러에서 쓸 수 있다.

Introduction


assert(3)는 개발자가 프로그램을 작성할 때, 버그가 생기는 것을 막아주는 가장 기초적인 방법 중의 하나입니다. TODO: assert()에 대해서 좀 더 설명

assert(3)의 출력은 정해지지 않아서, 컴파일러마다 조금씩 다릅니다만1, 대개의 경우, assert가 발생된 소스의 파일 이름과 줄 번호를 알려주면서 프로그램을 강제로 끝냅니다. 끝낼 때에는 abort(3)를 사용하도록 되어 있습니다.

예를 들어 아래의 출력은 어떤 시스템의 assert(3) 출력 결과입니다.
$ cat tmp.c
#include <assert.h>

void
adult_only(int age)
{
  assert(age > 18);
}

int
main(void)
{
  adult_only(3);
  return 0;
}
$ gcc tmp.c
$ ./a.out
a.out: tmp.c:6: adult_only: Assertion `age > 18' failed.
Aborted
$ _
assert()를 효과적으로 수행하기 위해서, 개발자가 직접 메시지를 써 넣을 수 있으면 참 편할 것이라 생각합니다. 즉 단순히 어떤 수식(위에서는 "age > 18")을 출력하고 종료하기 보다는, printf()와 같은 형식의 메시지도 함께 출력할 수 있다면 나중에 assert()가 발생할 때, 왜 발생했는지 이유를 빠르게 알아낼 수 있을 것입니다. 결국 우리가 만들고자 하는 것은 다음과 같은 코드를 만들 수 있게 하고:
xassert(age > 18, "AGE must be 19 at least. (age = %d)", age);
실제로 조건을 만족하지 않을 경우, 다음과 같은 메시지를 출력하게 하려는 것입니다:
a.out: tmp.c:6: adult_only: Assertion `age > 18' failed.
        AGE must be 19 at least. (age = 3)

Implementation

assert(3)는 매크로 NDEBUG가 정의되어 있는 경우, ((void)0)으로 확장되어 실제로 기계어 코드를 만들어내지 않습니다. 따라서 최대한 오버헤드를 적게 하기 위해서는 ASSERT도 다음과 같이 매크로 함수로 정의되어야 합니다.
#ifndef NDEBUG
# define xassert(x, ...)        /* 메시지 출력하고 종료.. */
#else
# define xassert(x, ...)        ((void)0)
#endif

가변 인자를 처리하는 매크로에 대해서는 CLanguageVariableArgumentsList에서 설명했습니다. 기억이 잘 나지 않는다면 다시 읽어보시기 바랍니다. 이제 위 코드에서 주석 부분을 써 넣어야 하는데, 다음과 같은 함수를 만들어서 대체하려고 합니다.
void
assert_(const char *filename, int lineno, const char *funcname,
        const char *expr, const char *format, ...)
{
  va_list ap;
  fflush(stdout);
  fprintf(stderr, "%s:%d: Assertion `%s' failed.\n",
          filename, lineno, expr);
  va_start(ap, format);
  vfprintf(stderr, format, ap);
  va_end(ap);
  fputc('\n', stderr);
  abort();
}
가변 인자를 처리하는 함수에 대해서 기억이 나지 않는다면, CLanguageVariableArgumentsList를 참고하기 바랍니다. 이제 xassert의 정의를 다음과 같이 다시 쓸 수 있습니다 (NDEBUG 관련 부분은 제외합니다):
void assert_(const char *filename, int lineno,
             const char *funcname,
             const char *expr, const char *format, ...);
#define xassert(x, ...) do {                                      \
                            if (!(x))                               \
                              assert_(__FILE__, __LINE__, __func__, \
                                      #x, __VA_ARGS__);             \
                        } while (0)

TODO: 몇가지 사용례 추가



Sources

xassert.h

/* $Id: xassert,v 1.12 2005/03/22 06:56:28 kss Exp kss $ */
/*
 * Enhanced assert(3)
 * Copyright (C) 2003, 2004  Seong-Kook Shin <cinsk.shin at samsung.com>
 */
                                                                                
#ifndef XASSERT_H_
#define XASSERT_H_
                                                                                
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
                                                                                
/* This indirect writing of extern "C" { ... } makes Emacs happy */
#ifndef BEGIN_C_DECLS
# ifdef __cplusplus
#  define BEGIN_C_DECLS  extern "C" {
#  define END_C_DECLS    }
# else
#  define BEGIN_C_DECLS
#  define END_C_DECLS
# endif
#endif /* BEGIN_C_DECLS */
                                                                                
BEGIN_C_DECLS
                                                                                
#ifndef NDEBUG
extern void assert_(const char *file, long line, const char *func,
                    const char *expr, const char *format, ...);
# define xassert(condition, ...)  do {                                        \
                                    if (!(condition))                         \
                                      assert_(__FILE__, __LINE__, __func__,   \
                                              #condition, __VA_ARGS__);       \
                                  } while (0)
                                                                                            
#else
# define xassert(condition, ...)  ((void)0)
#endif /* NDEBUG */
                                                                                            
                                                                                          
END_C_DECLS
                                                                                            
#endif /* XASSERT_H_ */

xassert.c

/* $Id: xassert,v 1.12 2005/03/22 06:56:28 kss Exp kss $ */
                                                                                            
/*
 * Enhanced assert(3)
 * Copyright (C) 2003, 2004  Seong-Kook Shin <cinsk.shin at samsung.com>
 */
                                                                                            
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
                                                                                            
#include <xassert.h>
                                                                                            
                                                                                            
void
assert_(const char *file, long line, const char *func,
        const char *expr, const char *format, ...)
{
  va_list ap;
                                                                                            
  fflush(stdout);
  fflush(stderr);               /* possibly redundant */
  fprintf(stderr, "%s:%ld: Assertion `%s' failed at %s.\n\t",
          file, line, expr, func);
  va_start(ap, format);
  vfprintf(stderr, format, ap);
  va_end(ap);
  fputc('\n', stderr);
  fflush(stderr);               /* possibly redundant */
  abort();
}
                                                                                            
                                                                                            
#ifdef TEST_XASSERT
int
main(void)
{
  int age = 1;
  ASSERT(age > 10, "Age should be larger than 10. (age = %d)", age);
  return 0;
}
#endif /* TEST_XASSERT */


ID
Password
Join
Let him who takes the Plunge remember to return it by Tuesday.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2005-03-22 15:56:28
Processing time 0.0016 sec