Как создать функцию только для отладки, которая принимает список переменных аргументов? Мне нравится printf ()

Большая часть кода, который мы пишем в интерфейсе JavaScript, основана на событиях - мы определяем какое-то поведение, а затем присоединяем его к событию, которое запускается пользователем (например, щелчком или нажатием). Наш код обычно прикрепляется как обратный вызов: одна функция, которая выполняется в ответ на событие. size12, size14 и size16 теперь являются функциями, которые будут изменять размер текста тела до 12, 14 и 16 пикселей соответственно. Мы можем прикрепить их к кнопкам (в данном случае ссылкам) следующим образом:

function makeSizer(size) {
    return function() {
    document.body.style.fontSize = size + 'px';
    };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

Fiddle

37
задан Brian Tompsett - 汤莱恩 30 January 2016 в 19:20
поделиться

10 ответов

Я все еще делаю это старый путь путем определения макроса (XTRACE, ниже), который коррелирует или к не или к вызов функции со списком аргумента переменной. Внутренне, назовите vsnprintf, таким образом, можно сохранить printf синтаксис:

#include <stdio.h>

void XTrace0(LPCTSTR lpszText)
{
   ::OutputDebugString(lpszText);
}

void XTrace(LPCTSTR lpszFormat, ...)
{
    va_list args;
    va_start(args, lpszFormat);
    int nBuf;
    TCHAR szBuffer[512]; // get rid of this hard-coded buffer
    nBuf = _vsnprintf(szBuffer, 511, lpszFormat, args);
    ::OutputDebugString(szBuffer);
    va_end(args);
}

Тогда типичный переключатель #ifdef:

#ifdef _DEBUG
#define XTRACE XTrace
#else
#define XTRACE
#endif

Хорошо, который может быть очищен вполне немного, но это - основная идея.

23
ответ дан Gunther Struyf 30 January 2016 в 19:20
поделиться

Другой интересный способ погасить функции variadic:

#define function sizeof
4
ответ дан Tim Cooper 30 January 2016 в 19:20
поделиться

Вот что-то, что я делаю в C/C++. Прежде всего Вы пишете функцию, которая использует материал varargs (см. ссылку в регистрации Stu). Тогда сделайте что-то вроде этого:


 int debug_printf( const char *fmt, ... );
 #if defined( DEBUG )
  #define DEBUG_PRINTF(x) debug_printf x
 #else
   #define DEBUG_PRINTF(x)
 #endif

 DEBUG_PRINTF(( "Format string that takes %s %s\n", "any number", "of args" ));

Все, что необходимо помнить, должно использовать дважды-parens при вызове функции отладки, и целая строка будет удалена в коде НЕОТЛАДКИ.

11
ответ дан Graeme Perrow 30 January 2016 в 19:20
поделиться

@CodingTheWheel:

существует одна небольшая проблема с Вашим подходом. Считайте вызов таким как

XTRACE("x=%d", x);

, Это хорошо работает в отладочной сборке, но в сборке конечных версий он расширится до:

("x=%d", x);

то, Которое является совершенно законным C и скомпилирует и обычно работать без побочных эффектов, но генерирует ненужный код. Подход, который я обычно использую для устранения той проблемы:

  1. Заставляют функцию XTrace возвратиться, интервал (просто возвращаются 0, возвращаемое значение не имеет значения)

  2. Изменение #define в #else пункте к:

    0 && XTrace
    

Теперь версия выпуска расширится до:

0 && XTrace("x=%d", x);

и любой достойный оптимизатор выбросит все это, так как оценка короткого замыкания предотвратила бы что-либо после & & от того, чтобы когда-нибудь быть выполняемым.

, Конечно, так же, как я записал, что последнее предложение, понял, что, возможно, исходная форма могла бы быть оптимизирована далеко также и в случае побочных эффектов, таких как вызовы функции, передал как параметры XTrace, это могло бы быть лучшее решение, так как это удостоверится, что отладочные версии и версии выпуска будут вести себя то же.

3
ответ дан Ferruccio 30 January 2016 в 19:20
поделиться

В C++ можно использовать оператор потоковой передачи для упрощения вещей:

#if defined _DEBUG

class Trace
{
public:
   static Trace &GetTrace () { static Trace trace; return trace; }
   Trace &operator << (int value) { /* output int */ return *this; }
   Trace &operator << (short value) { /* output short */ return *this; }
   Trace &operator << (Trace &(*function)(Trace &trace)) { return function (*this); }
   static Trace &Endl (Trace &trace) { /* write newline and flush output */ return trace; }
   // and so on
};

#define TRACE(message) Trace::GetTrace () << message << Trace::Endl

#else
#define TRACE(message)
#endif

и использование это как:

void Function (int param1, short param2)
{
   TRACE ("param1 = " << param1 << ", param2 = " << param2);
}

можно тогда реализовать настроенный вывод трассировки для классов почти таким же способом, которым Вы сделали бы это для вывода к std::cout.

2
ответ дан Tim Cooper 30 January 2016 в 19:20
поделиться

На каких платформах разве они не доступны? stdarg является частью стандартной библиотеки:

http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html

Любая платформа не, если это не стандарт C реализация (или очень, очень старое). Для тех необходимо будет использовать varargs:

http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html

1
ответ дан Stu 30 January 2016 в 19:20
поделиться

Это - то, как я действительно отлаживаю печать outs в C++. Определите 'dout' (отладка) как это:

#ifdef DEBUG
#define dout cout
#else
#define dout 0 && cout
#endif

В коде я использую 'dout' точно так же, как 'cout'.

dout << "in foobar with x= " << x << " and y= " << y << '\n';

, Если препроцессор заменяет 'dout' '0 & & суд' примечание это < < имеет более высокий приоритет, чем & & и оценка короткого замыкания & & заставляет целую строку оценить к 0. Так как этот 0 не используется, компилятор не генерирует кода вообще для той строки.

21
ответ дан sdcvvc 30 January 2016 в 19:20
поделиться

А-ч, vsprintf () был вещью, которую я пропускал. Я могу использовать это для передачи списка аргумента переменной непосредственно printf ():

#include <stdarg.h>
#include <stdio.h>

void DBG_PrintImpl(char * format, ...)
{
    char buffer[256];
    va_list args;
    va_start(args, format);
    vsprintf(buffer, format, args);
    printf("%s", buffer);
    va_end(args);
}

Тогда обертка все это в макросе.

2
ответ дан Jonathan Leffler 30 January 2016 в 19:20
поделиться

Часть проблемы с этим видом функциональности - то, что часто это требует variadic макросов. Они были стандартизированы справедливо недавно (C99), и много старых компиляторов C не поддерживает стандарт или имеет их собственную специальную работу вокруг.

Ниже заголовок отладки, я записал, что это имеет несколько замечательных функций:

  • Поддержки C99 и синтаксис C89 для макросов отладки
  • Позволяют/Запрещают вывод на основе Вывода аргумента функции
  • к дескриптору файла (файл io)

Примечание: По некоторым причинам у меня были некоторые небольшие проблемы форматирования кода.

#ifndef _DEBUG_H_
#define _DEBUG_H_
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "stdarg.h"
#include "stdio.h"

#define ENABLE 1
#define DISABLE 0

extern FILE* debug_fd;

int debug_file_init(char *file);
int debug_file_close(void);

#if HAVE_C99
#define PRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stdout, format, ##__VA_ARGS__); \
} \
}
#else
void PRINT(int enable, char *fmt, ...);
#endif

#if _DEBUG
#if HAVE_C99
#define DEBUG(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, "%s : %d " format, __FILE__, __LINE__, ##__VA_ARGS__); \
} \
}

#define DEBUGPRINT(x, format, ...) \
if ( x ) { \
if ( debug_fd != NULL ) { \
fprintf(debug_fd, format, ##__VA_ARGS__); \
} \
else { \
fprintf(stderr, format, ##__VA_ARGS__); \
} \
}
#else /* HAVE_C99 */

void DEBUG(int enable, char *fmt, ...);
void DEBUGPRINT(int enable, char *fmt, ...);

#endif /* HAVE_C99 */
#else /* _DEBUG */
#define DEBUG(x, format, ...)
#define DEBUGPRINT(x, format, ...)
#endif /* _DEBUG */

#endif /* _DEBUG_H_ */
1
ответ дан Jonathan Leffler 30 January 2016 в 19:20
поделиться

Взгляните на этот поток:

Это должно ответить на Ваш вопрос.

1
ответ дан Community 27 November 2019 в 03:36
поделиться