Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Вызов функции с неопределенным количеством аргументов  (Прочитано 14508 раз)
0 Пользователей и 4 Гостей смотрят эту тему.
s_n
Постоялец

ru
Offline Offline

« : 01-09-2006 12:21 » 

День добрый.

Есть такой вопрос: пишу врапер для библиотеки, необходимо обернуть функцию с переменным колличеством аргументов, к примеру:
  void func(char * str, ...);
Определяю в классе метод
  func_wraper(char * str, ...);
вопрос в том как мне из моей функции func_wraper вызвать оригинальную func, передав ей все аргументы (список аргументов состоит из строк и заканчивается терминатором, допустим NULL)?

Допустим аргументы я вытащил, получился у меня массив char * arg[] как мне вызвать функцию func(arg[0], arg[1], arg[2], .... , arg[n]), если n заранее неизвестен?

Я нашел единственный выход: создаю массив определенного размера, char * arg[30], и вызываю func(arg[0], arg[1], ..., arg[30]), если пользватель передал меньше тридцати параметров, то arg[n] будет содержать терминатор, и остальные члены будут проигнорированны оригинальной функцией, если больше 30 - пользователь идет лесом.
Но слишком уж убого получается.

В теории есть еще такой вариант с привлечением ассемблера (функция stdcall):
Заводится void * retaddr; , делается pop retaddr. теперь в стеке лежит только набор параметров.
делается call func, получается я полностью передаю все аргументы. после возвращения из func делается push retaddr - возврашаем аддрес возврата на место. теперь можно вызывать return.

Но неуверен, что получиться да и кросплатформенность при этом накрывается.

Может что подскажите?
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 01-09-2006 13:29 » 

В стандартной библиотеке из этого выкрутились создав набор ф-ий: одни принимают переменное число параметров, другие принимают массив и его длину. Чтобы быть точнее нужно в доку глянуть.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #2 : 01-09-2006 14:00 » new

может это поможет
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_va_arg.2c_.va_end.2c_.va_start.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_crt_va_arg.2c_.va_end.2c_.va_start.asp
Записан

Странно всё это....
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 01-09-2006 14:03 » 

LogRus, эти макросы нужны для разбора переменных параметров внутри ф-ии, принимающей их.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 01-09-2006 14:17 » 

В стандартной библиотеке языка Си для функций printf, fprintf, sprintf, которые принимают переменное число аргументов, введены функции vprintf, vfprintf, vsprintf, которые вместо многоточия принимают аргумент типа va_list. Тип va_list определяет реализационно зависимое представление параметров функции в стеке. 
Именно эти функции используются в обёртках вокруг функций печати.
Код:
int my_printf(const char * format,...) {
    va_list arg_list;
    int result;
    va_start( arg_list, format );
    result = vprintf(format, arg_list);
    va_end( arg_list );
    return result;
}

Если у твоей функции нет аналога с параметром типа va_list, то увы.  Нет переносимого способа передать переменное число аргументов без перечисления самых аргументов.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 02-09-2006 14:12 » 

Параметры ф-ий переменного числа параметров (вида func(arg1, arg2, ...)) обрабатываются компилатором. Соотв. для создания своей обертки можно использовать макрос. Вот примеры из документации gcc:
Код:
#define debug(format, ...)  printf(stderr, format, __VA_ARGS__)

#define debug(format, args...)  printf(stderr, format, args)

#define debug(format, ...)  printf(stderr, format, ## __VA_ARGS__)
Первый пример соответствует стандарту ISO C 1999.
Второй и третий - расширение gcc.

Такой метод подходит для ограниченного применения.
Код:
int real_func(int a, ...); // result = a + ...

#define my_func(arg1, arg2, ...) real_func(arg1 * arg2, __VA_LIST__)
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 04-09-2006 08:47 » 

Век живи, век учись Улыбаюсь

Спасибо за инфу!
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines