Войти
ПрограммированиеФорумОбщее

Движок на Си (14 стр)

Advanced: Тема повышенной сложности или важная.

Страницы: 113 14 15 1618 Следующая »
#195
7:50, 27 июня 2019

exchg
Спасибо, немного не то, я видно не смог тогда мысль правильно выразить.
Можно ли в "автоматическом" режиме, "другим кодом", вызвать список функций, с разным колвом и типом аргументов.

int f1(int a)
int f2(int *a)
int f3(void)
int f4(int b, int c)
int f5(Mesh* m)

в вашем случае вы руками проставляете параметры сами
func(123);                                   
func(321, 321); 


#196
8:37, 27 июня 2019

u960
> Можно ли в "автоматическом" режиме, "другим кодом", вызвать список функций, с
> разным колвом и типом аргументов.

А откуда эти параметры да еще и разные берутся?

#197
10:23, 27 июня 2019

=A=L=X=
> А откуда эти параметры да еще и разные берутся?

Задача-желание были такие:
Есть очень много разных механик, и для каждой механики нужны разные данные, разные ресурсы.

init_cars(max_cars, cars_models)
init_specials_monsters(void)
int_crash_walls(player, blast_effect)
и .тд
и так же функции логики-отрисовки, если что специальное для данной механики.

И все это работает, если функции вызывать ручками. Но допустим машины нужны на 10 уровне игры, стены на пятом,а сам ты начинаешь в пещере с монстрами, если упростить.

Можно конечно в лоб, и все в таком духе:

if (level == 10) {
    init_cars(max_cars, cars_models)
} else if (level == 5) {
    int_crash_walls(player, blast_effect)
}
else
....
и тд

#198
(Правка: 12:18) 11:51, 27 июня 2019

#!
> ого, да это же основа для event-driven
Да, вполне.

> в своё время по незнанию использовал boost::bind/boost::apply
В C++ этого нету. В С++ func() это аналог func(void) в Си. С некоторым эффектом в С++ ты можешь использовать func(...) для таких целей, но придется список аргументов раскручивать руками.

=A=L=X=
> В Си же от рождения были некоторые "проблемы" со строгой типизацией.
Не может быть проблем с тем чего нету.

u960
> Можно ли в "автоматическом" режиме, "другим кодом", вызвать список функций, с
> разным колвом и типом аргументов
Тогда я повторю вопрос =A=L=X=
> А откуда эти параметры да еще и разные берутся?

Покажи псевдокодом откуда ты их достаешь и как ты их хранишь. Я вот так сразу не пойму. Если ты имеешь в виду некий диспетчер по можешь прокидывать в выбранную функцию аргументы приходящие снаружи через va_list

#199
(Правка: 16:49) 16:32, 27 июня 2019

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

я вот пока навскидку вижу затруднения с п.3. т.к. остатки типизации в Си могут не давать вызывать подобным образом:

int f5(Mesh* m);
uint8_t buffer[100500];
memcpy(buffer, m, meshSize);
f = f5;
f(buffer);
хотя.. это у меня зашквар, так всё работает т.к. сигнатура f5 оказывается скрытой и ругаться не на что

#200
(Правка: 17:43) 17:10, 27 июня 2019

#!
> 1. связываем аргументы с функцией которая должна их обработать
> 2. кладём получившееся в контейнер, для событий обычно очередь, но вот у u960
> это может быть просто массив или хеш-таблица
> 3. просто дёргаем функцию
Ну так я не совсем понимаю что нужно то в итоге. Но если то, что выше, то можно примерно вот так:

typedef struct disp
{
    void (*callback)();
    void* arg;
} disp_t;


typedef struct arg1
{
    int count;
    char* name;
} arg_func1_t;


typedef struct arg2
{
    double value[3];
} arg_func2_t;


static void func1(arg_func1_t* a);
static void func2(arg_func2_t* a);


static disp_t table[] =
{
    {func1, &(arg_func1_t){.count = 123, .name = "some name"}},
    {func2, &(arg_func2_t){.value = {.1, .2, .3}}},
    {func1, &(arg_func1_t){.count = 325, .name = "test"}},
};


static
void func1(arg_func1_t* a)
{
    printf("%s:%d: '%s' -> %u:'%s'\n",
           __FILE__, __LINE__, __func__,
           a->count, a->name
        );
}

static
void func2(arg_func2_t* a)
{
    printf("%s:%d: '%s' -> [%f, %f, %f]\n",
           __FILE__, __LINE__, __func__,
           a->value[0], a->value[1], a->value[2]
        );
}


int main()
{
    size_t u;
    for (u=0; u<3; ++u)
        table[u].callback(table[u].arg);
}

Эт чисто как иллюстрация идеи. А даьше добавляй сколь нужно любых функций со своими любыми аргументами.

#201
(Правка: 18:00) 17:54, 27 июня 2019

exchg
> можно примерно вот так
по мне так то что надо, пожалуй даже запишу себе в блокнотик

а я тут по наивности попытался что-то делать с указателем на функцию, например записать адрес в плоский буфер, потом вытащить, типа сериализовать функцию
вот ещё весёлый топик на эту тему

#202
(Правка: 19:59) 19:34, 27 июня 2019

Всё ещё есть возможность вызывать функции, складывая аргументы в стёк ручками. Правда, для каждой платформы придется реализовывать это самому, и это не сработает с fastcall. Это основа маршаллинга практически в любом скриптовом языке:

#define PUSH_ARG(arg) __asm push arg;
#define INVOKE(func) __asm call func;

...

void marshalFunction(const char* func, script_param_t* params, int param_num)
{
  int i;

  for(i = param_num - 1; i >= 0; i—)
    PUSH_ARG(marshalParam(params[i]));

  INVOKE(func);
}

#203
0:19, 28 июня 2019

exchg
> Ну так я не совсем понимаю что нужно то в итоге. Но если то, что выше, то можно
> примерно вот так:

Вы правильно все поняли, только, хотелось чтобы функции

static void func1(arg_func1_t* a);
static void func2(arg_func2_t* a);

имели раздельные параметры

static void func1(int count, char *name);
static void func2(float a, float b, float c);

чтобы изначально функции разрабатывались с таким интерфейсом, могли отдельно вызываться "руками". 

А так да, потом добавить их в таблицу, список, как в вашем примере.

#204
(Правка: 1:18) 1:02, 28 июня 2019

u960
> хотелось чтобы функции
До нового года еще далеко. )))

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

> А так да, потом добавить их в таблицу, список, как в вашем примере.
Ну покажи как ты их собираешься добавить и хранить в таблице ))))

Вообще если упороться, то можешь посмотреть в <stdarg.h> и окажется, что аргументы раскручиваются банальным макросом. Дальше можешь руками/скриптом упаковать параметры в таблицу подобным манером (это просто линейный список аргументов с рекастами), потом пушить их на стек руками по примеру monobogdan. И это будет работать по крайней мере для 32 бит.. Но такое можно делать ради "любви к искусству" и с ручным "управлением" раскладкой под разные платформы. Если нада для дела, то так не нада делать.

#205
2:23, 28 июня 2019

u960

Самый обобщённый вариант такой задачи это "из скрипта вызвать произвольную функцию на компилируемом языке".
То есть и имя функции и состав её аргументов (при условии совпадения по типам и количеству) формируется совершенно динамически.
Но мы согласны с тем, что существует совершенно нативная функция на целевом языке (Си в нашем случае) без пенальти на вызов из него самого.
В такой формулировке я бы поступал примерно так как действует DCOM - заводил бы обобщённую функцию вида:

void invoke( variant_array *args, variant *res );
в которой был бы некий маппинг на нативные функции через промежуточный слой кода. в том же DCOM он автоматически генерируется из некоего промежуточного описательного текстового формата (.idl) чтобы легко было поддерживать эту связь между нативным и "скриптовым" кодом. но в DCOM возможны трюки типа ассемблерных вставок, а если мы полностью кроссплатформенны, то видимо придётся генерировать полностью тела этих функций в каждом конкретном случае подставляя потом их единого формата указатели в лукап-таблицу. Хотя тут есть возможность генерировать только одну функцию-распрыжку для каждой спецификации функции. Так или иначе вызов такой функции через invoke - вещь как и полагается в скриптах сравнительно затратная - каждый раз производится сверка состава и количества аргументов.

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

#206
3:54, 28 июня 2019

u960
> if (level == 10)

геймдиз: Вася а где можно такой-то параметр поменять?
Вася: тут у меня в коде калбэк
геймдиз: #$%%^ в задницу..
+ Показать
#207
8:46, 28 июня 2019

=A=L=X=
OLE вещь крутая, но по своему медленная - обычно никто не реализовывает getidsofnames, а отдаёт это RTTI или генераторам кода. Маршаллинг ручками по моему примеру будет быстрее, и должен работать и на x86, и на x64. С ARM(и другими RISC 32х битными камнями) ситуация чуть другая - там всё распихивается по регистрам, поэтому тем же препроцессором достаточно заменить номер регистра на свой.

#208
9:42, 28 июня 2019

monobogdan

Ты еще забываешь, что бывает не только ARM или x86, но и Visual C++ и GCC, поэтому на асме хардкорить конечно круто, если оно того стоит, но кроссплатформенность и кросскомпиляторность снижается сильно.

#209
10:31, 28 июня 2019

exchg
> Ну покажи как ты их собираешься добавить и хранить в таблице ))))
то есть, это не рабочий вариант, и это вы просто так накидали

+ Показать

monobogdan
>Всё ещё есть возможность вызывать функции, складывая аргументы в стёк ручками. Правда, для >каждой платформы придется реализовывать это самому, и это не сработает с fastcall. Это основа >маршаллинга практически в любом скриптовом языке

Вроде похоже на то, что я хочу, а я хочу просто вызывать функции с разными параметрами.
А можно где нить по подробнее прочитать? прежде чем я начну задавать глупые вопросы.

=A=L=X=
>А откуда эти параметры да еще и разные берутся?
не очень понял вопроса, но я же где то располагаю переменные

int max_cars = 5;
MODEL cars_models[5];

init_cars(max_cars, cars_models);
Страницы: 113 14 15 1618 Следующая »
ПрограммированиеФорумОбщее