Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 06:50
Оценка:
Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.

1) Сначала я хотел сделать это через функцию которая вызывает и fprint и printf, но обнаружил что чтобы это сделать необходимо определить число передаваемых параметров и их типы по строке форматирования... в итоге был напсин код на асме который успешно сохраняет кусочек стека в heapе а потом шаманит с указателем стека и вызывает printf и fprint. Все бы нечиго, я даже заделал макрос, который генерит соответсвующие asmные вставки, но по каким то причинам слово Assembler кроме меня никому не греет душу

2) Возникла идея, что раз нельзя что бы функция ето все тварила, то пусть хотя бы макрос, что ему стоит строчке в тексте слепить, но обнаружилось что препроцессор C++ такой ущербный язык, что кажется его таким сделал специально — 'ибо нефиг' . В результате нескольких попыток, был получен слегка корявый вариант, который все таки слепляет агрументы из двух списков для функции с переменным числом агрументов:

// Бубен :)
#define __AST *
#define Cc __AST/  //Comment Close
#define Co /__AST  //Comment Open
#define _FUNCCALL(func, h, t) func(Co h Cc, Co t Cc)
// Конец Бубна

// Целывой макрос
FILE* logFile = 0;
#define LOGPRINT(x) \
   printf##x; \
   if (logFile) _FUNCCALL(fprintf, (Cc logFile Co), x);

// Используется как
LOGPRINT((Cc "Error code: %d. Error Message: %s\r\n", errCode, errMsg Co))


ВОПРОС: Есть у кого идеи как всетаки сделать макрос LOGPRINT чтобы его можно было записать:
LOGPRINT(("Error code: %d. Error Message: %s\r\n", errCode, errMsg)), т.е. без Cc и Co.
а то не красиво смотрится

Кто подскажеть тому



18.08.05 11:38: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
Re: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 06:53
Оценка:
Сори! Обшибся набирая..

Правильный тескт макроса

// Целывой макрос
FILE* logFile = 0;
#define LOGPRINT(x) \
   printf( Co x Cc ); \       // здесь было printf##x
   if (logFile) _FUNCCALL(fprintf, (Cc logFile Co), x);
Re: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:09
Оценка:
Здравствуйте, vnechiporenko, Вы писали:


V>Кто подскажеть тому


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

#ifdef _DEBUG
#define LOGPRINT myFunc
#else
#define LOGPRINT 1 ? (void)0 : myFunc
#endif

LOGPRINT("Error code: %d. Error Message: %s\r\n", errCode, errMsg);
Имею скафандр — готов путешествовать!
Re[2]: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 07:33
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Здравствуйте, vnechiporenko, Вы писали:



V>>Кто подскажеть тому


RB>Напиши свою функцию с параметром-строкй и переменным числом аргументов, которая будет вызывать vfprintf.

RB>Далее стандартно...

RB>#ifdef _DEBUG

RB> #define LOGPRINT myFunc
RB>#else
RB> #define LOGPRINT 1 ? (void)0 : myFunc
RB>#endif

RB>LOGPRINT("Error code: %d. Error Message: %s\r\n", errCode, errMsg);


Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .
Re[3]: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:39
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V> Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .


Ты пишешь под абстрактного коня в вакууме, или под конкретную систему?
Имею скафандр — готов путешествовать!
Re[3]: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:42
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V> Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .


Впрочем, неважно.

1. Функции типа vfprintf используют va_list для просмотра аргументов.

2. Если подобных функций нет, можно взять готовый код разбора аргументов. Смотри ATLString или MFC CString::Format
Имею скафандр — готов путешествовать!
Re[3]: Препроцессор и переменное число аргументов
От: Аноним  
Дата: 18.08.05 07:51
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

в принципе ссылка уже дана, но на всякий случай
кому лень искать, должно быть примерно так
void Trace( const char *szFormat, ... )
{
va_list arg;
va_start( arg, szFormat ); // Initialize variable arguments
char sMessage[ 1024 ] = { '\0' };
::vsprintf( sMessage, szFormat, arg );
va_end( arg ); // Reset variable arguments
::strcat( sMessage, "\r\n" );

// далее sMessage в файл
}
Re[4]: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 08:02
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>1. Функции типа vfprintf используют va_list для просмотра аргументов.

Сори ступил Я только сейчас прочел про vfprintf (не знал о ё суфществовании), действительно рулит... Её спецом похоже для этих целей сделали.

RB>2. Если подобных функций нет, можно взять готовый код разбора аргументов. Смотри ATLString или MFC CString::Format

Угу.. и это дельный совет

Thanks,
Re: Препроцессор и переменное число аргументов
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 18.08.05 10:30
Оценка: 3 (1)
Здравствуйте, vnechiporenko, Вы писали:

V>Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.


V>ВОПРОС: Есть у кого идеи как всетаки сделать макрос LOGPRINT чтобы его можно было записать:

V>LOGPRINT(("Error code: %d. Error Message: %s\r\n", errCode, errMsg)), т.е. без Cc и Co.
V>а то не красиво смотрится

В библиотеке ACE это уже давно сделано. Вот пример логирования из их Basic_Types_Test.cpp:
ACE_ERROR ((LM_ERROR, ACE_TEXT ("assertion failed \"%s\": %u != %u\n"),
                        message, i, j));


Вот здесь можно посмотреть, как это сделано: http://www.dre.vanderbilt.edu/Doxygen/Stable/ace/Log__Msg_8h.html#a4
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 18.08.05 11:14
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V>Сори ступил


Ничего страшного Ты не один.
Я тоже не знал о ее существовании, и тоже хотел логирование с форматной строкой сделать, как в printf. А выкрутился установкой исходника MS CRT и компиляцией модифицированной CRT! Был жутко доволен своей изобретательностью, пока не узнал про vprintf
Re: Препроцессор и переменное число аргументов
От: pavel_turbin  
Дата: 18.08.05 11:15
Оценка:
вроде бы в Linux-e (gcc?) такой наворот есть.
Re[4]: Препроцессор и переменное число аргументов
От: degor Россия  
Дата: 18.08.05 11:21
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Ты пишешь под абстрактного коня в вакууме, или под конкретную систему?

сферического коня в вакууме
Re[2]: Препроцессор и переменное число аргументов
От: arcman Россия  
Дата: 19.08.05 13:11
Оценка:
Здравствуйте, pavel_turbin, Вы писали:

_>вроде бы в Linux-e (gcc?) такой наворот есть.

Не только есть, но и прекрасно используется
Макрос с переменным числом параметров — почти как функция.
Удобно — жуть как, незаменим для дебуга
Re: Препроцессор и переменное число аргументов
От: WinterMute Россия http://yarrr.ru
Дата: 19.08.05 15:07
Оценка: 2 (1) +1
IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:

class LogOutput
{
   ...
};
LogOutput log_print;

log_print << "text: " << 5;
Re[3]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 19.08.05 16:29
Оценка:
Здравствуйте, arcman, Вы писали:

A>Не только есть, но и прекрасно используется

A>Макрос с переменным числом параметров — почти как функция.
A>Удобно — жуть как, незаменим для дебуга

Слушай, расскажи поподробнее?
Re[2]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 19.08.05 16:32
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:


WM>
WM>class LogOutput
WM>{
WM>   ...
WM>};
WM>LogOutput log_print;

WM>log_print << "text: " << 5;
WM>


Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?
И под C не покатит, так что может оно и лучше, но не так универсально.
Re[3]: Препроцессор и переменное число аргументов
От: Centaur Россия  
Дата: 20.08.05 02:37
Оценка:
Здравствуйте, Сергей, Вы писали:

WM>>IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:


WM>>
WM>>log_print << "text: " << 5;
WM>>


С>Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?


class null_ostream
{
public:
  template <typename T>
  null_ostream& operator<<(const T&) const
  {}
};

#ifdef WITH_LOGGING
log_ostream log_print;
#else
null_ostream log_print;
#endif

Дальше, оптимизирующий компилятор все обращения к log_print в нелогирующей версии выоптимизирует до нуля.
Re: Препроцессор и переменное число аргументов
От: vdimas Россия  
Дата: 20.08.05 07:28
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V>Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.


[...]
V>Кто подскажеть тому

А почему бы не сделать шаблонные заготовки ф-ий, до, скажем, 15-20 аргументов.

типа:
#ifdef DEBUG
#    define LOGPRINT_FUNC printf
#else
#    define LOGPRINT_FUNC empty_func
inline void empty_func(...) {}
#endif

template<typename T1>
inline LOGPRINT(T1 t1) {
    LOGPRINT_FUNC(t1);
}

template<typename T1, typename T2>
inline LOGPRINT(T1 t1, T2 t2) {
    LOGPRINT_FUNC(t1, t2);
}

// и т.д.


empty_func(...) — пустая, будет "проглочена" компилятором в релизе.
Re[3]: Препроцессор и переменное число аргументов
От: pavel_turbin  
Дата: 21.08.05 10:30
Оценка:
Здравствуйте, arcman, Вы писали:

A>Здравствуйте, pavel_turbin, Вы писали:


_>>вроде бы в Linux-e (gcc?) такой наворот есть.

A>Не только есть, но и прекрасно используется
A>Макрос с переменным числом параметров — почти как функция.
A>Удобно — жуть как, незаменим для дебуга

что делает код непортируемый в Windows, т.к. cl не имеет такой поддержки.
Re[4]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 08:19
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Дальше, оптимизирующий компилятор все обращения к log_print в нелогирующей версии выоптимизирует до нуля.

Не факт.
Боюсь, оптимизатор может не справиться с таким случаем (для этого компилятору пришлось бы доказать, что ни одна из non_inline_functionX не имеет побочных эффектов; может быть, что глобальная оптимизация с этим и справится, но гарантии нет):
null_stream() << non_inline_function1() + non_inline_function2()/non_inline_function3();
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.