assert
макрос (он должен быть один, чтобы дать __LINE__
и __FILE__
Информация).
Вы можете указать свой собственный. Я бы назвал это что-то другое, как tassert
для удобства понимания, возможно, как (непроверенный код)
#ifdef NDEBUG
#define tassert(Cond) do {if (0 && (Cond)) {}; } while(0)
#else
#define tassert_at(Cond,Fil,Lin) do { if ((Cond)) { \
time_t now##Lin = time(NULL); \
char tbuf##Lin [64]; struct tm tm##Lin; \
localtime_r(&now##Lin, &tm##Lin); \
strftime (tbuf##Lin, sizeof(tbuf##Lin), \
"%Y-%m-%d,%T", &tm##Lin); \
fprintf(stderr, "tassert %s failure: %s %s:%d\n", \
#Cond, tbuf##Lin, Fil, Lin); \
abort(); }} while(0)
#define tassert(Cond) tassert_at(Cond,__FILE__,__LINE__)
#endif /*NDEBUG*/
Я использую cpp concatenation##
с Lin
снизить вероятность конфликтов имен, и я использую cpp stringification#
сделать строку из of Cond
макрос формальный. Cond
всегда расширяется, чтобы убедиться, что в нем синтаксические ошибки компилятора улавливают даже при отключении tassert
с NDEBUG
как assert(3).
В некоторой функции можно поместить большую часть кода в вышеуказанный макрос, например.
void tassert_at_failure (const char* cond, const char* fil, int lin) {
timer_t now = time(NULL);
char tbuf[64]; struct tm tm;
localtime_r (&now, &tm);
strftime (tbuf, sizeof(tbuf), "%Y-%m-%d,%T", &tm);
fprintf (stderr, "tassert %s failure: %s %s:%d\n",
cond, tbuf, fil, lin);
abort();
}
, а затем просто определить (немного как <assert.h>
делает ...)
#define tassert_at(Cond,Fil,Lin) do { if ((Cond)) { \
tassert_at_failure(#Cond, Fil, Lin); }} while(0)
, но я не люблю много этот подход, потому что для отладки с gdb
, имеющей abort()
вызывается в макросе намного проще (размер кода IMHO для отладки исполняемых файлов вообще не имеет значения, вызов abort
в макросе намного удобнее внутри gdb
- создание более коротких обратных трасс и исключение одной команды down
...). Если вы не хотите переносить мобильность libc
и используете только последний GNU libc
, вы можете просто переопределить функцию __assert_fail
Glibc (см. Внутри заголовочный файл <assert.h>
). YMMV.
BTW, в реальном коде на C++ Я предпочитаю использовать <<
для подобных отладочным выводам. Это позволяет использование моих собственных operator <<
выводя подпрограмм (если вы даете его в качестве дополнительного макро аргумента), так что я имею в виду (непроверенного кода!)
#define tassert_message_at(Cond,Out,Fil,Lin) \
do { if ((Cond)) { \
time_t now##Lin = time(NULL); \
char tbuf##Lin [64]; struct tm tm##Lin; \
localtime_r(&now##Lin, &tm##Lin); \
strftime (tbuf##Lin, sizeof(tbuf##Lin), \
"%Y-%m-%d,%T", &tm##Lin); \
std::clog << "assert " << #Cond << " failed " \
tbuf##Lin << " " << Fil << ":" << Lin \
<< Out << std::endl; \
abort(); } } while(0)
#define tassert_message(Cond,Out) \
tassert_message_at(Cond,Out,__FILE__,__LINE__)
, а затем я хотел бы использовать tassert_message(i>5,"i=" << i);
BTW, вам возможно, захотите использовать syslog(3) вместо fprintf
в вашем tassert_at
макросе.
оберните свой собственный ASSERT сверху утверждения и запишите время журнала – billz