Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.04.2014, 15:30   #1
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию Вариативный макрос для логгирования

Доброе время суток!

Понадобилось мне тут написать простенький логгер, но захотелось сделать обёртку макросную (ф-ию как-то не хочу делать, не аккуратненько же )... перерыл весь инет, собрал такой вот код:
Код:
// реализации логирования для 1..9 параметров
#define GET_COUNT(x, _1, _2, _3, _4, _5, _6, _7, _8, _9, COUNT, ... ) COUNT

#define LOG(...) \
	GET_COUNT(, ##__VA_ARGS__, \
	_LOG_9(__VA_ARGS__), \
	_LOG_8(__VA_ARGS__), \
	_LOG_7(__VA_ARGS__), \
	_LOG_6(__VA_ARGS__), \
	_LOG_5(__VA_ARGS__), \
	_LOG_4(__VA_ARGS__), \
	_LOG_3(__VA_ARGS__), \
	_LOG_2(__VA_ARGS__), \
	_LOG_1(__VA_ARGS__))
Пробовал и др. варианты (они предпочтительнее, но откатывать сил нет уже), НО во всех вариантах код "_LOG_*(__VA_ARGS__)" не работает... тупо __VA_ARGS__ не разворачивается до исходных аргументов, просто превращается в строку с аргументами (если параметры "1, 2", то получаем "_LOG_2( "1, 2" )", вместо "_LOG_2(1, 2)")

У кого какие идеи? использую MSVS2010
GreenWizard вне форума Ответить с цитированием
Старый 18.04.2014, 16:07   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,708
По умолчанию

Цитата:
НО во всех вариантах код "_LOG_*(__VA_ARGS__)" не работает... тупо __VA_ARGS__ не разворачивается до исходных аргументов
Не надо гнать на компилятор коль доки не читаем.

http://msdn.microsoft.com/ru-ru/library/ms177415.aspx
Цитата:
__VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.
"1, 2" - это строка, это один параметр

Последний раз редактировалось p51x; 18.04.2014 в 16:09.
p51x вне форума Ответить с цитированием
Старый 18.04.2014, 16:45   #3
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Код:
#include "stdafx.h"
#include <iostream>

#define GET_COUNT(_1, _2, _3, _4, _5, _6, _7, _8, _9, COUNT, ... ) COUNT

#define PLUS_TEXT_(x,y) x ## y
#define PLUS_TEXT(x, y) PLUS_TEXT_(x, y)

#define CHECK2(A, B) printf(A, B);
#define MACRO(...) \
	PLUS_TEXT(CHECK, GET_COUNT(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1))(__VA_ARGS__)

int _tmain(int argc, _TCHAR* argv[])
{
	MACRO("%d hi\n", 5);
	system("pause");
	return 0;
}
MACRO("%d hi\n", 5) => PLUS_TEXT(CHECK, GET_COUNT(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1))(__VA_ARGS__) => PLUS_TEXT(CHECK, 2)(__VA_ARGS__) => CHECK2(__VA_ARGS__) => упс, а где второй параметр? получаем CHECK2(("%d hi\n", 5), ) => printf("%d hi\n", 5, а тут пустой параметр В);; =>
warning C4003: not enough actual parameters for macro 'CHECK2'
error C2059: syntax error : ')'

ну и как разбить __VA_ARGS__ на А и В?
GreenWizard вне форума Ответить с цитированием
Старый 18.04.2014, 21:50   #4
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

http://www.cplusplus.com/reference/cstdarg/va_arg/
Не? Вместо макроса.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 18.04.2014, 23:07   #5
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
http://www.cplusplus.com/reference/cstdarg/va_arg/
Не? Вместо макроса.
ну так, отличие функций от макроса вам же известно) кроме того, даже printf-у нужно указывать тип аргументов, а макросы могут развернуться в "stream << value" и компилятор уже сам попытается найти как преобразовать данные
да и тут дело уже в спортивном интересе.... люди вон хешируют строки константные в compile-time, а тут примитивная задача, по-моему
GreenWizard вне форума Ответить с цитированием
Старый 19.04.2014, 02:18   #6
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Правдами и неправдами, но решил я задачу! Хотел добавить ещё вывод типов переменных, но что-то не работает ни typeof, ни decltype.

Вот такой код получился (упростил до std::cout, но не проблема использовать др. поток для вывода):
Код:
#include "stdafx.h"
#include <iostream>
#include <string>
// хак для получения N-ого аргумента макроса
#define ARG_1(_1, ...) _1
#define ARG_2(_1, _2, ...) _2
#define ARG_3(_1, _2, _3, ...) _3
#define ARG_4(_1, _2, _3, _4, ...) _4
#define ARG_5(_1, _2, _3, _4, _5, ...) _5
#define ARG_6(_1, _2, _3, _4, _5, _6, ...) _6
#define ARG_7(_1, _2, _3, _4, _5, _6, _7, ...) _7
#define ARG_8(_1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define ARG_9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
// для подсчёта количества аргументов
#define GET_COUNT(_1, _2, _3, _4, _5, _6, _7, _8, _9, COUNT, ... ) COUNT
// сервисные макросы 
#define PLUS_TEXT_(x,y) x ## y
#define PLUS_TEXT(x, y) PLUS_TEXT_(x, y)
#define MAKE_TEXT_(x) #x
#define MAKE_TEXT(x) MAKE_TEXT_(x)
///////////////
// начало лога
#define _log_start \
	std::cout << "Line #" MAKE_TEXT(__LINE__) "\n"
// вывод информации о переменной
#define _log(value) \
	<< MAKE_TEXT(value)" = "<< value << "\n"
// логгирование одной переменной
#define LOG1(...) \
	_log_start \
	_log(ARG_1(__VA_ARGS__))
// логгирование двух переменных
#define LOG2(...) \
	_log_start \
	_log(ARG_1(__VA_ARGS__)) \
	_log(ARG_2(__VA_ARGS__))

// логгирование трёх переменных
#define LOG3(...) \
	_log_start \
	_log(ARG_1(__VA_ARGS__)) \
	_log(ARG_2(__VA_ARGS__)) \
	_log(ARG_3(__VA_ARGS__))
// ....................................
// рекурсии нет в макросах, поэтому разворачиваем обработку каждого 
// варианта макроса
// ....................................
// главный макрос, который уже запускает описанную выше махину
#define LOG(...) \
	PLUS_TEXT(LOG, GET_COUNT(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)) (__VA_ARGS__)

// тестовая программа
int _tmain(int argc, _TCHAR* argv[])
{
	int x =  5;
	double y = 2.3;
	char *z = "test string";
	std::string s("bla-bla-bla");
	
	LOG(x);
	LOG(y, z);
	LOG(z, x, y);
//	LOG(z, x, y, s); <= ошибка т. к. не описал я LOG4
	LOG(s);

	system("pause");
	return 0;
}
Вывод программы:
Код:
Line #54
x = 5
Line #55
y = 2.3
z = test string
Line #56
z = test string
x = 5
y = 2.3
Line #57
s = bla-bla-bla
"Развёртка" строк с макросами:
Код:
	std::cout << "Line #" "54" "\n" << "x"" = "<< x << "\n";
	std::cout << "Line #" "55" "\n" << "y"" = "<< y << "\n" << "z"" = "<< z << "\n";
	std::cout << "Line #" "56" "\n" << "z"" = "<< z << "\n" << "x"" = "<< x << "\n" << "y"" = "<< y << "\n";
	std::cout << "Line #" "57" "\n" << "s"" = "<< s << "\n";
Тут, конечно, есть вопросы о целесообразности/вредности объединения строк (меньше вызовов vs больший расход памяти), но потерь не избежать при логгирование.

Мораль сей басни: если очень хочется, но ты одинок, то С++ всегда поможет
GreenWizard вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
PasteLink - простой макрос на VBA для Excel для вставки в ячейку гипперссылки на файл в буфере обмена. wyfinger Microsoft Office Excel 4 22.05.2013 14:10
Макрос для копирования данных из формы для формирования таблицы xander2112 Microsoft Office Excel 12 06.05.2013 22:23
Нужен макрос для CORELDRAW 11 для автоматизации процесса Ergashboy Фриланс 0 23.02.2012 22:22
для работы написать макрос для Excel и Word.... smanna Microsoft Office Excel 2 30.11.2010 12:43
Надо макрос для Excel для перестановки букв dionisprf Microsoft Office Excel 2 10.06.2009 06:04