Как передать (...) дальше
От: Аноним  
Дата: 10.12.04 08:24
Оценка:
Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?

Что-то типа:
void MyPrintf( char *format, ...)
{
   char s[1000] = "My: ";
   strcat( s, format);

   printf( s, /*А что же здесь?*/);

}
Re: Как передать (...) дальше
От: Кодт Россия  
Дата: 10.12.04 08:31
Оценка: 12 (1) +1
Здравствуйте, Аноним, Вы писали:

А>Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?


1) смотри семейство vprintf/vsprintf/vfprintf
2) делается так
void vfoo(const char* fmt, va_list args)
{
  .....
  int x = va_arg(args,int);
  .....
}

void foo(const char* fmt, ...)
{
  .....
  va_list args;
  va_start(args,fmt);
  vfoo(fmt,args);
  va_end(args);
  .....
}
Перекуём баги на фичи!
Re: Как передать (...) дальше
От: co  
Дата: 10.12.04 08:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?


А>Что-то типа:

А>
А>void MyPrintf( char *format, ...)
А>{
А>   char s[1000] = "My: ";
А>   strcat( s, format);

А>   printf( s, /*А что же здесь?*/);

А>}
А>


Конкретно здесь можно использовать ф-ю vsprintf. Другая проблема это запихнуть в printf неизвестное число параметров, приходящее в ф-юю в виде например вектора. Я её решал с помощью хака.
Re: Как передать (...) дальше
От: korzhik Россия  
Дата: 10.12.04 08:33
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?


А>Что-то типа:

А>
А>void MyPrintf( char *format, ...)
А>{
А>   char s[1000] = "My: ";
А>   strcat( s, format);

А>   printf( s, /*А что же здесь?*/);

А>}
А>


1. Использовать ф-ю vprintf
int vprintf( const char *format, va_list argptr);


примерно так:
void MyPrintf(char *format, ...)
{
    va_list vargs;
    va_start(vargs, format);

    vprintf(format, &vargs);
    va_end(vargs);
}


2. Если же задача стоит чётко, как именно передать аргументы из внешней функции использующей ellipsis во внутреннюю, также использующую ellipsis, то это можно сделать только если твой компилятор поддерживает переменное число параметров в макросах, в gcc это вроде бы должно выглядеть так:
#define MyPrintf(fmt, args...) printf(fmt, ##args );
Re: Как передать (...) дальше
От: G.I. O_Neil Россия  
Дата: 10.12.04 08:41
Оценка:
Здравствуйте, Аноним, Вы писали:

Что-то типа:
void MyPrintf( char *format, ...)
{
   char s[1000] = "My: ";
   strcat( s, format);

va_list arg;
va_start(arg, format);
   printf( s, format, arg );
va_end(arg);
}
Don't crash the ambulance, whatever you do!
ICQ#327823673
In her dealings with man Destiny never closed her accounts. (c) Oscar Wilde
Re[2]: Как передать (...) дальше
От: Аноним  
Дата: 10.12.04 08:44
Оценка:
Здравствуйте, korzhik, Вы писали:

K>2. Если же задача стоит чётко, как именно передать аргументы из внешней функции использующей ellipsis во внутреннюю, также использующую ellipsis, то это можно сделать только если твой компилятор поддерживает переменное число параметров в макросах, в gcc это вроде бы должно выглядеть так:

K>
K>#define MyPrintf(fmt, args...) printf(fmt, ##args );
K>


Именно так задача и стоит. Пример с printf-ом просто первое что пришло в голову. Функция должна принимать именно (...), а не va_list.

А можно ли обойтись без макросов, а именно функцией, которая просто транзитом передает набор аргументов дальше (ну там делает еще свои дела предварительно)?
Re[3]: Как передать (...) дальше
От: Кодт Россия  
Дата: 10.12.04 08:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Именно так задача и стоит. Пример с printf-ом просто первое что пришло в голову. Функция должна принимать именно (...), а не va_list.


А>А можно ли обойтись без макросов, а именно функцией, которая просто транзитом передает набор аргументов дальше (ну там делает еще свои дела предварительно)?


Только через хак.
Или, если ты знаешь, что там не более N параметров и типы их известны на стадии компиляции — то запихать их все (возможно, с пустышками).
prepare_ints(int n, ...)
{
  assert(n>0 && n<10);
  int data[10];
  va_list args; va_start(args,n);
  for(int i=0; i<min(n,10); ++i) data[i] = va_arg(args,int);
  va_end(args);
  send_ints(n, data[0]*1, data[1]*2, ....., data[9]*10);
}
Перекуём баги на фичи!
Re[4]: Как передать (...) дальше
От: Аноним  
Дата: 10.12.04 09:02
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Только через хак.

Понятно. Очень жаль

К>Или, если ты знаешь, что там не более N параметров и типы их известны на стадии компиляции — то запихать их все (возможно, с пустышками).

Да нет, это уже совсем изврат получается.

Спасибо всем ответившим!
Re[3]: Как передать (...) дальше
От: korzhik Россия  
Дата: 10.12.04 09:04
Оценка:
Здравствуйте, Аноним, Вы писали:

K>>2. Если же задача стоит чётко, как именно передать аргументы из внешней функции использующей ellipsis во внутреннюю, также использующую ellipsis


А>Именно так задача и стоит. Пример с printf-ом просто первое что пришло в голову. Функция должна принимать именно (...), а не va_list.

А>А можно ли обойтись без макросов, а именно функцией, которая просто транзитом передает набор аргументов дальше (ну там делает еще свои дела предварительно)?

хммм, сейчас решения не знаю, думать надо однако
Думаю что в общем случае,даже если решение существует, оно врятли будет переносимо и красиво.

Единственное что может облегчить задачу, это если ты можешь менять код внутренней функции.
Тогда в неё можно передать указатель на va_list.

Или менять дизайн.
Re[3]: Как передать (...) дальше
От: G.I. O_Neil Россия  
Дата: 10.12.04 09:04
Оценка:
Здравствуйте, Аноним,

А>А можно ли обойтись без макросов, а именно функцией, которая просто транзитом передает набор аргументов дальше (ну там делает еще свои дела предварительно)?


ИМХО нет.
Don't crash the ambulance, whatever you do!
ICQ#327823673
In her dealings with man Destiny never closed her accounts. (c) Oscar Wilde
Re[5]: Как передать (...) дальше
От: Кодт Россия  
Дата: 10.12.04 09:06
Оценка:
Здравствуйте, Аноним, Вы писали:

К>>Только через хак.

А>Понятно. Очень жаль

К>>Или, если ты знаешь, что там не более N параметров и типы их известны на стадии компиляции — то запихать их все (возможно, с пустышками).

А>Да нет, это уже совсем изврат получается.

Неужели нельзя переделать всё так, чтобы без эллипса было? Или ты к сторонней библиотеке что-то прикручиваешь?
Перекуём баги на фичи!
Re[6]: Как передать (...) дальше
От: Аноним  
Дата: 10.12.04 09:25
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Неужели нельзя переделать всё так, чтобы без эллипса было? Или ты к сторонней библиотеке что-то прикручиваешь?

Можно. Все исходники доступны для правки.
Просто в исходной функции было так:


Send( int objectId, int nParam, ...)
{

}

и она юзалась из методов класса
class Object
{
  //......

  int id;

};

void Object::F()
{
  //.....
  Send( id, 4, 1,2,3,4);


}


А мне захотелось добавить в класс Object метод Send, который бы просто добавлял свой id и перенаправлял запрос библиотечной ф-ии:
void Object::Send( int nParam, ...)
{
  //.....
  ::Send( id, nParam, ...);
}


Думал что можно это сделать легко. Оказалось — нет.

K>Или менять дизайн.

Будем менять.

Кстати, как в приведенном примере это элегантнее сделать?
Только без va_list.
Re[7]: Как передать (...) дальше
От: Hroftina Россия  
Дата: 10.12.04 09:34
Оценка:
А может, можно на ассемблере вставку сляпать, которая все полученные параметры в стек упихает, а потом ее вызвать?
Re[7]: Как передать (...) дальше
От: Кодт Россия  
Дата: 10.12.04 09:56
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Кодт, Вы писали:

К>>Неужели нельзя переделать всё так, чтобы без эллипса было? Или ты к сторонней библиотеке что-то прикручиваешь?

А>Можно. Все исходники доступны для правки.


Вопрос номер раз: Принимает ли ::Send гомогенные или гетерогенные данные? Например, произвольное количество int'ов или некую мешанину типов?

Вопрос номер два: Можно ли гомогенизировать данные естественным образом? Например, у printf — это приведение к строковому типу.

Вопрос номер три: можно ли выполнить декомпозицию? Например, printf можно разложить на последовательность операций с каждым данным по отдельности, как, например, вывод в cout<<x<<y<<z



Посылку переменной длины можно упаковать в контейнер — например, vector или list.
Гетерогенные данные — или привести к гомогенному виду (к той же строке), или обернуть — например, VARIANT, boost::any и т.п., или сделать шаблон функции, принимающей их.
Перекуём баги на фичи!
Re[7]: Как передать (...) дальше
От: korzhik Россия  
Дата: 10.12.04 10:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Можно. Все исходники доступны для правки.


тогда, не изменяя интерфейса, можно сделать следующее:
передавать внутренней функции указатель на va_list, примерно так:
  void MyPrintf(const char *format, ...)
  {
    va_list vargs;
    va_start(vargs, format);
    foo(format, &vargs);
    va_end(vargs);
  }

  void foo(const char *format, ...)
  {
    va_list vargs;
    va_list *vargsparam;

    va_start(vargs, format);
    vargsparam = va_arg(vargs, va_list*);

    // здесь мы имеем доступ к va_list внешней функции через (*vargsparam)

    va_end(vargs);
  }
Re: Как передать (...) дальше
От: Olegator  
Дата: 14.12.04 13:09
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?


А что, если поиграться со стеком:

void MyPrintf(const char* fmt, ...)
{
    char s[1000] = "My: ";
    std::strcat(s, fmt);

    fmt = s;

    __asm mov esp, ebp
    __asm add esp, 8
    __asm call printf
}


Главное -- оно всё работает, и printf прекрасно всё выводит. Вот только после такой "игры" MSVC ругается, что стек вокруг s порушен . Может кто знает, как решить эту проблему?

Я пытался. Записывал в esp старое значение. Но в этом случае... программа замирала! Под отладчиком видел, что esp постоянно меняется .

С уважением,
Olegator
... << Rsdn@Home 1.1.4 beta 1 >>
Re[8]: Как передать (...) дальше
От: korzhik Россия  
Дата: 14.12.04 15:08
Оценка:
Здравствуйте, korzhik, Вы писали:

K>Здравствуйте, Аноним, Вы писали:


А>>Можно. Все исходники доступны для правки.


K>тогда, не изменяя интерфейса, можно сделать следующее:

воспользоваться шаблонами как здесь
Автор: korzhik
Дата: 14.12.04
Re: Как передать (...) дальше
От: McQwerty Россия  
Дата: 14.12.04 15:18
Оценка: 24 (3)
Здравствуйте, Аноним, Вы писали:

А>Можно ли из функции, принимающей переменное число параметров, передать все эти параметры в другую функцию с переменным числом параметров?


А>Что-то типа:

А>
А>void MyPrintf( char *format, ...)
А>{
А>   char s[1000] = "My: ";
А>   strcat( s, format);

А>   printf( s, /*А что же здесь?*/);

А>}
А>


У меня получилось вот так:
struct xxx
{
    char x [1024];
// 1024 - волшебное число. Общий размер передаваемых параметров
}; // xxx

void ell (char* fmt, ...)
{
    va_list vargs;
    va_start(vargs, fmt);

    vprintf (fmt, vargs);

    xxx* p = (xxx*) vargs;

    printf (fmt, * p);
    va_end (vargs);
} // ell

int main(int argc, char* argv[])
{
    ell ("[%s %d %d %f]\n", "Hello world", 1, 2, 3.4);

    return 0;
}


Вывод такой:

[Hello world 1 2 3.400000]
[Hello world 1 2 3.400000]
Press any key to continue

Re[2]: Как передать (...) дальше
От: Кодт Россия  
Дата: 15.12.04 08:11
Оценка:
Здравствуйте, McQwerty, Вы писали:

А>>Что-то типа:


Ну ты хитёр!
Перекуём баги на фичи!
Re[2]: Как передать (...) дальше
От: Olegator  
Дата: 15.12.04 13:24
Оценка:
Ну так всё-таки? Хотя бы объясните мне, почему происходит ошибка, очень уж интересна мне эта тема.
... << Rsdn@Home 1.1.4 beta 1 >>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.