Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> va_args,__VA_ARGS__ и enum, Как избавиться от макроса при ... 
:(
    Опции темы
flagist0
Дата 1.11.2007, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 29.10.2007

Репутация: нет
Всего: нет



Есть функции вывода и логгирования ошибок - void error(int level, const char* msg, ...) и log.printf(const char *msg, ...). Обе принимают параметры в стиле printf - форматная строка и имена параметров.
Еще есть переменные int debug_lvl и log_lvl, хранящие уровни вывода (например, мы можем выводить только fatal error'ы и ничего не логгить). Уровни сообщений хранятся в enum DebugMsg{Disabled=-1,FatalError=0, Error,Warning,Message};
Нужна функция, которая будет в зависимости от текущих уровней вызывать error и log.printf. 
Например, void log_and_error(DebugMsg lvl,const char* msg), то есть принимаем уровень выводимого сообщения и УЖЕ скомпонованное с помощью sprintf'a сообщение;или void log_and_error(DebugMsg lvl,const char* msg, ...) - то же самое, но параметры мы должны передавать сами.

Соответственно, два вопроса на выбор  smile :

1.Чтобы не делать руками перед каждым вызовом log_and_error sprintf(expanded_msg,"Watch for %s added [descriptor=%d].\n",filenames[wd],wd)), я написал мааленький макрос, который это делает сам - 
#define _log_and_error(lvl,...) {sprintf(expanded_msg,__VA_ARGS__);log_and_error(lvl,expanded_msg);}
В нем используется __VA_ARGS__ (C99) и естественно ничего не работает. gcc (4.2.0) говорит :предупреждение: cannot pass objects of non-POD type ‘struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >’ through ‘...’; call will abort at runtime  и в самом деле вылетает (Недопустимая инструкция). видимо дело в перечислении.

2. В случае log_and_error(DebugMsg lvl,const char* msg, ...), как же цивилизованно передать все параметры после lvl error и log?? Насколько я понял у Страуструпа, надо знать их тип, но мне не нужен разбор, мне нужно их просто передать функциям дальше!!

Заранее спасиб, извините за спам smile



Это сообщение отредактировал(а) flagist0 - 1.11.2007, 15:16
PM MAIL GTalk   Вверх
JackYF
Дата 1.11.2007, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(flagist0 @  1.11.2007,  15:14 Найти цитируемый пост)
filenames[wd],wd

filenames[wd].c_str(), ws.c_str()

попробуй.


Вопрос в пустоту: а может, стоит отказаться от этой практики и заюзать boost::format - более прозрачное и типобезопасное решение?


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
xvr
Дата 1.11.2007, 15:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(flagist0 @ 1.11.2007,  15:14)
Есть функции вывода и логгирования ошибок - void error(int level, const char* msg, ...) и log.printf(const char *msg, ...). Обе принимают параметры в стиле printf - форматная строка и имена параметров.
Еще есть переменные int debug_lvl и log_lvl, хранящие уровни вывода (например, мы можем выводить только fatal error'ы и ничего не логгить). Уровни сообщений хранятся в enum DebugMsg{Disabled=-1,FatalError=0, Error,Warning,Message};
Нужна функция, которая будет в зависимости от текущих уровней вызывать error и log.printf. 

Соответственно, два вопроса на выбор  smile :

1.Чтобы не делать руками перед каждым вызовом log_and_error sprintf(expanded_msg,"Watch for %s added [descriptor=%d].\n",filenames[wd],wd)), я написал мааленький макрос, который это делает сам - 
#define _log_and_error(lvl,...) {sprintf(expanded_msg,__VA_ARGS__);log_and_error(lvl,expanded_msg);}
В нем используется __VA_ARGS__ (C99) и естественно ничего не работает. gcc (4.2.0) говорит :предупреждение: cannot pass objects of non-POD type ‘struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >’ through ‘...’; call will abort at runtime  и в самом деле вылетает (Недопустимая инструкция). видимо дело в перечислении.

2. В случае log_and_error(DebugMsg lvl,const char* msg, ...), как же цивилизованно передать все параметры после lvl error и log?? Насколько я понял у Страуструпа, надо знать их тип, но мне не нужен разбор, мне нужно их просто передать функциям дальше!!

В данном случае можно просто отформатировать строку самому, а дальше ее передать уже в виде строки целиком, а не в виде формата и набора параметров:
Код

void log_and_error(DebugMsg lvl,const char* msg, ...)
{
 va_list p;
 va_start(p,msg);
 string message=vprn(msg,p); // see 'utils.h'
 va_end(p);
 if (...) error(lvl,"%s",message.c_str());
 if (...) log.printf("%s",message.c_str());
}

Что касается передачи string в ... - то это работать будет, но не так, как ожидалось - спецификатор параметра %s в printf принимает строку с C стиле (char*), а string, да еще и переданный по значению, это совсем не то же самое smile


Это сообщение отредактировал(а) xvr - 1.11.2007, 15:32
PM MAIL   Вверх
flagist0
Дата 1.11.2007, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 29.10.2007

Репутация: нет
Всего: нет



Цитата

filenames[wd].c_str(), ws.c_str()

попробуй.

Извиняюсь, криво выразился. 
Код

sprintf(expanded_msg,"Watch for %s added [descriptor=%d].\n",filenames[wd],wd))
 - это просто пример формирования строки с ошибкой перед закидыванием ее в log_and_error.
Вопрос в том, как не загрязнять код sprintf'ами перед каждым выводом через log_and_error. Если бы sprintf возвращал бы указатель на сформированную строку, то я бы писал
Код

log_and_error(Message,sprintf(форматная_строка,прм1,прм2));

А приходится писать 
Код

sprintf(преобразованная_строка,"форматная_строка",прм1,прм2);
log_and_error(Message,преобразованная строка);

Я реализовал это в виде макроса _log_and_error, но ведь наверное есть лучший вариант?

Цитата

Вопрос в пустоту: а может, стоит отказаться от этой практики и заюзать boost::format - более прозрачное и типобезопасное решение?

Вполне возможно. Во всяком случае boost::lambda где-то в проекте уже используется. smile

PM MAIL GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0519 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.