LINUX.ORG.RU

Вызов функций с различным числом аргументов по адресу.

 ,


0

2

Призываю любителей и пользователей языка Ц.
Допустим, есть функции:

int a(int arg1, int arg2)
{
    ...
}

int b(int arg1, int arg2,int arg3)
{
    ...
}
Как написать такую функцию, которая могла бы вызывать функции по указателю, но с разным числом аргументов? Типа такого:
call_function(a,2,arg1,arg2);
call_function(b,3,arg3,arg4,arg5);
Единственное, что мне приходит на ум - это сделать switch по кол-ву аргументов и для каждого количества использовать свой тип указателя. Может есть какие-нибудь директивы компилятора, прагмы, аналог arguments из javascript или еще чего?

Мне кажется, что ты что-то делаешь не так.

Deleted
()

копай в сторону VA_ARG Пример на С++


#include <stdio.h>      /* printf */
#include <stdarg.h>     /* va_list, va_start, va_arg, va_end */

int FindMax (int n, ...)
{
  int i,val,largest;
  va_list vl;
  va_start(vl,n);
  largest=va_arg(vl,int);
  for (i=1;i<n;i++)
  {
    val=va_arg(vl,int);
    largest=(largest>val)?largest:val;
  }
  va_end(vl);
  return largest;
}

int main ()
{
  int m;
  m= FindMax (7,702,422,631,834,892,104,772);
  printf ("The largest value is: %d\n",m);
  return 0;
}

ymuv ★★★★
()
Последнее исправление: ymuv (всего исправлений: 1)

Думаю ответа на вопрос «зачем?» мы не услышим.
1. В C-ях нету перегрузки имен функции, а значит в игру вступает елипсис.
2. Будет один большой свитч на все случаи жизни.(если принять что сигнатура функции вычисляется по кол-ву аргументов)

Раз уж очень надо то напрашивается макрос.

FeyFre ★★★★
()

Где-то ошибка в дизайне. Так делать не нужно, потому что это не поддерживаемо, и не переносимо. Но если очень хочется, то только макро-магия, и пачка дефайнов.

joy4eg ★★★★★
()
Ответ на: комментарий от anonymous

Про stdarg и VA_ARG знаю, это не то. Мне нужно вызывать различные функции (ядра) зная только их адрес и кол-во аргументов, это обычные функции с фиксированным кол-вом аргументов.
Зачем? Если получится - напишу отдельно. Да забыл тэг «хочется странного».

Rupricht ★★
() автор топика

Я даже боюсь спросить зачем это понадобилось, но да, тут нужен элипсис. Ну можно ещё реализовать список и подавать аргументы в нём. Не на много меньший изврат чем постановка задачи.

Выглядеть это будет примерно так (на основе ymuv):

#include <stdio.h>
#include <stdarg.h>

typedef int (*sum_ptr)(int a, ...);

int sum(int n, ...)
{
  va_list vl;
  int sum, i;

  va_start(vl,n);
  sum = 0;
  for(i=0;i<n;i++)
    sum += va_arg(vl,int);
  va_end(vl);

  return sum;
}

int main ()
{
  sum_ptr sum_func = sum;

  printf ("%d\n", sum_func(2, 1, 2));
  printf ("%d\n", sum_func(5, 1, 2, 3, 4, 5));
  return 0;
}

А ещё лучше описать проблему, которая навела на такие мысли, и мы подумаем как решить её по-человечески.

alexanius ★★
()
Ответ на: комментарий от Rupricht

ИМХО, проще написать на каждую функцию обертку.

joy4eg ★★★★★
()
Ответ на: комментарий от Rupricht

Не зря боялся спрашивать «зачем» :) Можно по подробнее? Сколько функций, какие типы аргументов (все одинаковые и различаются только количеством или нет), в каких условиях вызываются (произвольные в цикле из массива, просто одиночные вызовы)? Может достаточно просто сделать парочку typedef'ов и работать как с обычными функциями? Пример точки вызова очень помог бы.

alexanius ★★
()
Ответ на: комментарий от alexanius

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

Rupricht ★★
() автор топика
Ответ на: комментарий от Rupricht

Возможно в ядре что-то такое есть уже для обозначения сигнатур?
Если нету - то тебе скорее надо генератор для var-args сделать. Можно сделать ассемблерный враппер наверно

mittorn ★★★★★
()

va_list можно только принять и прочитать, сформировать его явно нельзя. Тебе нужен свитч по сигнатуре; если их ограниченное количество, то он не будет большим. Для общего вида надо юзать платформ-специфику типа libffi.

http://www.atmark-techno.com/~yashi/libffi.html#Simple-Example

arturpub ★★
()

В университете делал такое в рамках типового задания по расширению возможностей калькулятора на flex/bison. Остановился на ассемблерной версии, которая реализовала соглашение вызовов cdecl и AMD64 call ABI. Если количество целевых платформ ограничено, то дело несложное, смотришь соглашение о вызове нужных функций и просто его реализуешь, оформляешь в виде *.s файла.

anonymous
()
Ответ на: комментарий от Rupricht

Мне нужно вызывать различные функции (ядра) зная только их адрес и кол-во аргументов, это обычные функции с фиксированным кол-вом аргументов.

Что это за функции-ядра? Может им, как в CL, придумать какой-нибудь SetArg(n, ...);? :)

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Функции ядра линукс. Одно дело придумать, только кто это в gcc продвинет?
Хочу пока обойтись без ассемблера. Придется делать switch, видимо.

Rupricht ★★
() автор топика

Поройся в доках GCC, точно были функции для работы с call фреймами,может там. Или как вариант нелокальные переходы glibc

MKuznetsov ★★★★★
()
Ответ на: комментарий от Rupricht

А, вот оно что. А вызывать ты их тоже из контекста ядра собрался? Или из юзерспейса? А функции эти - не системные вызовы случаем?)

libffi тебе помог бы, наверное, но вот в случае с ядром - не знаю даже.

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Конечно из пространства ядра, в этом вся фишка.

Rupricht ★★
() автор топика
Ответ на: комментарий от Rupricht

Величайший из великих.

Нихрена не понял. В чём твоя проблема?

call_function(a,2,arg1,arg2);
call_function(b,3,arg3,arg4,arg5);
//Это делается проще паренной репы:
#define call(fun, args...) ({fun(args);})

Тебе надо рантайм? То же - в чём проблема? Судя по «указатель на каждое ко-вол елементов» - ты не знаешь о type(*)(), либо что?

В рантайме кто будет вызывать твою обёртку с нужным кол-вом аргументов? Зачем тебе ещё свич, если он там и так будет - моё предположение выше верно?

anonymous
()
Ответ на: комментарий от anonymous

Зачем мне что-то писать на этой помойке?

anonymous
()

Средствами языка С вряд ли это сделать. Если только не писать функции с таким прототипом: <return type> foo (va_list args); Тогда всё очевидно. А иначе можно сделать вставочку на ассемблере, где будет прыжок на нужную функцию

anonymous
()
Ответ на: комментарий от Rupricht

Сделай типа хедерник, в котором будет в каждой строке по одной функции, завернутой в некий неопределенный заранее макрос, типа MACRO_NAME(rettype,func,...), макрос будет вариадик.

Занятые в конце строки не ставь.

Дальше сделай юнион, в который вместо тела инклюдь заголовок с макросами.

Перед тем, как инклюдить файл, определи несколько макросов, чтобы в результате инклюда в юнионе получились бы структуры с аргументами и возвращаемым значением.

Аналогичным образом сделай диспетчер вызовов фукций(можно через свич, а можно через массив указателей).

anonymous
()
Ответ на: комментарий от anonymous

Макросы не нужны, мне в рантайме надо.

Rupricht ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.