Передать массив в функцию по значению
От: stas19t  
Дата: 01.09.10 06:33
Оценка:
Добрый день!
Есть потребность вызывать функции с неизвестным числом параметров.
Я делаю это так:
// cast pointer to delegate
typedef void* (*AnyFunc)(...);
AnyFunc userFunc = AnyFunc(funcPtr);


Параметры для userFunc у меня в массиве.
Чтобы вызвать userFunc, я использую switch:
    // call user defined function
    void* result; 
    switch (argsCount)
    {
    case 0:
        result = userFunc(); 
        break;
    case 1:
        result = userFunc(args[0]); 
        break;
    case 2:
        result = userFunc(args[0], args[1]); 
        break;
.... и т.д.

Этот код работает. Но хотелось бы обойтись без switch на 255 кейсов.
Реальные функции на вход могут принимать различное число параметров. Например, как-то так:
int MyFunc1(int p1, int p2) { return p1+p2; } // изменить эти функции возможности нет.
int MyFunc2(int p1) { return p1*p1; }


Если передавать тупо массив вот так:
result = userFunc(args);

то, насколько я понимаю, передается не сам массив, а ссылка на него.
Поэтому у меня ничего не работает.
Посоветуйте пожалуйста, возможно ли как-то красиво решить эту проблему?

Спасибо!

п.с.: понадобилось сделать такой изврат, т.к. нужно обращаться к user defined functions созданных для excel. функции находятся в dll. на врод они на самом деле принимают переменное число указателей на struct XLOPER12, а не int, как в моих примерах.
Re: Передать массив в функцию по значению
От: stas19t  
Дата: 01.09.10 08:17
Оценка:
Так тоже не получается:


    public struct Array {
        int el[2];
    } ar;
    ar.el[0] = 1;
    ar.el[1] = 2;
    void* result = userFunc(ar);



В окне Disassembly выглядит это вот так:


    public struct Array {
        int el[3];
    } ar;

    ar.el[1] = 1;
0000015e  mov         dword ptr [rsp+000000F4h],1 
    ar.el[2] = 2;
00000169  mov         dword ptr [rsp+000000F8h],2 
    void* result = userFunc(ar);
00000174  mov         r11,83CD720h 
0000017e  mov         r10,qword ptr [rsp+28h] 
00000183  lea         rcx,[rsp+000000F0h] 
0000018b  mov         rax,qword ptr [rcx] 
0000018e  mov         qword ptr [rsp+60h],rax 
00000193  mov         eax,dword ptr [rcx+8] 
00000196  mov         dword ptr [rsp+68h],eax 
0000019a  lea         rcx,[rsp+60h] 
0000019f  call        000000000867A524
Re[2]: Передать массив в функцию по значению
От: stas19t  
Дата: 01.09.10 08:22
Оценка:
Здравствуйте, stas19t, Вы писали:

S>Так тоже не получается:



S>
S>    public struct Array {
S>        int el[2];
S>    } ar;
S>    ar.el[0] = 1;
S>    ar.el[1] = 2;
S>    void* result = userFunc(ar);
S>



S>В окне Disassembly выглядит это вот так:



S>
S>    public struct Array {
S>        int el[3];
S>    } ar;

S>    ar.el[1] = 1;
S>0000015e  mov         dword ptr [rsp+000000F4h],1 
S>    ar.el[2] = 2;
S>00000169  mov         dword ptr [rsp+000000F8h],2 
S>    void* result = userFunc(ar);
S>00000174  mov         r11,83CD720h 
S>0000017e  mov         r10,qword ptr [rsp+28h] 
S>00000183  lea         rcx,[rsp+000000F0h] 
S>0000018b  mov         rax,qword ptr [rcx] 
S>0000018e  mov         qword ptr [rsp+60h],rax 
S>00000193  mov         eax,dword ptr [rcx+8] 
S>00000196  mov         dword ptr [rsp+68h],eax 
S>0000019a  lea         rcx,[rsp+60h] 
S>0000019f  call        000000000867A524 

S>


Для сравнения:
void* result = userFunc(ar.el[1], ar.el[2]);
00000183 mov ecx,dword ptr [rsp+000000E4h]
0000018a mov edx,dword ptr [rsp+000000E8h]
00000191 mov r11,822FE20h
0000019b mov r10,qword ptr [rsp+28h]
000001a0 call 000000000868A524
Re[2]: Передать массив в функцию по значению
От: Ytz https://github.com/mtrempoltsev
Дата: 01.09.10 08:22
Оценка:
Здравствуйте, stas19t, Вы писали:

S>Так тоже не получается:



S>
S>    public struct Array {
S>        int el[2];
S>    } ar;
S>


Друг, это не С и не С++
Re: Передать массив в функцию по значению
От: szag  
Дата: 01.09.10 08:22
Оценка:
Здравствуйте, stas19t, Вы писали:

S>Добрый день!

S>Есть потребность вызывать функции с неизвестным числом параметров.

была таже проблема, мне помог вот такой вариант.
Автор: Sni4ok
Дата: 06.08.10
Re: Передать массив в функцию по значению
От: Abyx Россия  
Дата: 01.09.10 08:23
Оценка: 4 (1)
Здравствуйте, stas19t, Вы писали:

S>Добрый день!

S>Есть потребность вызывать функции с неизвестным числом параметров.

используйте boost.fusion, функцию invoke
In Zen We Trust
Re: Передать массив в функцию по значению
От: Pavel Dvorkin Россия  
Дата: 01.09.10 15:51
Оценка:
Здравствуйте, stas19t, Вы писали:


S>Если передавать тупо массив вот так:

S>
S>result = userFunc(args);
S>

S>то, насколько я понимаю, передается не сам массив, а ссылка на него.

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

Рассмотрим, как вызов происходит. Аргументы засылаются в стек, после чего происходит переход по адресу функции.

2 аргумента — 2 команды push, 4 -вргумента — 4 push.

Так что массив здесь вообще не поможет.

S>Поэтому у меня ничего не работает.

S>Посоветуйте пожалуйста, возможно ли как-то красиво решить эту проблему?

С помощью асмовской вставки можно. Заслать эти аргументы в стек и вызвать как функцию без аргументов.
With best regards
Pavel Dvorkin
Re[3]: Передать массив в функцию по значению
От: stas19t  
Дата: 01.09.10 17:16
Оценка:
Здравствуйте, Ytz, Вы писали:

Ytz>Здравствуйте, stas19t, Вы писали:


S>>Так тоже не получается:



S>>
S>>    public struct Array {
S>>        int el[2];
S>>    } ar;
S>>


Ytz>Друг, это не С и не С++



Да . Спалился. На самом деле пишу на unsafe managed c++.
Re: Передать массив в функцию по значению
От: stas19t  
Дата: 01.09.10 17:19
Оценка:
szag, Abyx, Pavel Dvorkin!
Спасибо за советы!
С boost я знаком слабо. С asm тоже поверхностно.
Видимо пока оставлю switch и положу себе на стек этот вопрос, т.к. очевидно он потребует вложений времени несколько больше чем ожидалось.
Постараюсь разобраться в вопросе. Отпишусь.
Re[2]: Передать массив в функцию по значению
От: igna Россия  
Дата: 02.09.10 11:08
Оценка:
Здравствуйте, stas19t, Вы писали:

S>С boost я знаком слабо.


Прочитал совет of Abyx
Автор: Abyx
Дата: 01.09.10
, попробовал, работает:


#include <iostream>
using namespace std;

#include <boost/fusion/include/array.hpp>
#include <boost/fusion/include/invoke.hpp>

void f(int i, int j, int k)
{
  cout << i << ' ' << j << ' ' << k << '\n';
}

int main()
{
  int a[] = { 1, 2, 3 };
  boost::fusion::invoke(f, a);
}


Ранее Fusion не использовал, так что может и со "слабым знакомством" пойдет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.