Большая часть кода, который мы пишем в интерфейсе 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;
Я все еще делаю это старый путь путем определения макроса (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
Хорошо, который может быть очищен вполне немного, но это - основная идея.
Другой интересный способ погасить функции variadic:
#define function sizeof
Вот что-то, что я делаю в 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 при вызове функции отладки, и целая строка будет удалена в коде НЕОТЛАДКИ.
@CodingTheWheel:
существует одна небольшая проблема с Вашим подходом. Считайте вызов таким как
XTRACE("x=%d", x);
, Это хорошо работает в отладочной сборке, но в сборке конечных версий он расширится до:
("x=%d", x);
то, Которое является совершенно законным C и скомпилирует и обычно работать без побочных эффектов, но генерирует ненужный код. Подход, который я обычно использую для устранения той проблемы:
Заставляют функцию XTrace возвратиться, интервал (просто возвращаются 0, возвращаемое значение не имеет значения)
Изменение #define в #else пункте к:
0 && XTrace
Теперь версия выпуска расширится до:
0 && XTrace("x=%d", x);
и любой достойный оптимизатор выбросит все это, так как оценка короткого замыкания предотвратила бы что-либо после & & от того, чтобы когда-нибудь быть выполняемым.
, Конечно, так же, как я записал, что последнее предложение, понял, что, возможно, исходная форма могла бы быть оптимизирована далеко также и в случае побочных эффектов, таких как вызовы функции, передал как параметры XTrace, это могло бы быть лучшее решение, так как это удостоверится, что отладочные версии и версии выпуска будут вести себя то же.
В 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
.
На каких платформах разве они не доступны? stdarg является частью стандартной библиотеки:
http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html
Любая платформа не, если это не стандарт C реализация (или очень, очень старое). Для тех необходимо будет использовать varargs:
http://opengroup.org/onlinepubs/007908775/xsh/varargs.h.html
Это - то, как я действительно отлаживаю печать 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 не используется, компилятор не генерирует кода вообще для той строки.
А-ч, 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);
}
Тогда обертка все это в макросе.
Часть проблемы с этим видом функциональности - то, что часто это требует variadic макросов. Они были стандартизированы справедливо недавно (C99), и много старых компиляторов C не поддерживает стандарт или имеет их собственную специальную работу вокруг.
Ниже заголовок отладки, я записал, что это имеет несколько замечательных функций:
Примечание: По некоторым причинам у меня были некоторые небольшие проблемы форматирования кода.
#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_ */
Взгляните на этот поток:
Это должно ответить на Ваш вопрос.