Tell me how to call a function with parameters not defined in advance. That is, I have an array, for example, int arr [15], and I want to pass all the elements of the array as parameters. But the problem is that the array can be of any size. Functions have the form int a (int a, int b, int c ...), it is required to call them having this array. Of course, you can pass an array to a function and not do extra work, but you want to simplify writing functions and make normal parameters, rather than pulling values ​​out of an array. The last time I solved this porblem is through assembler inserts of function parameters and its call. Perhaps there is a simpler method?

UPD. Still, I wonder why the compiler cannot be told that I want to call the void * test function, with a floating number of parameters, here are their number and here are the pointers to variables. Through the assembler it is done easily. Not much more dangerous than va_list.

  • 2
    > Of course, you can pass an array to a function and not do extra work, but I want to simplify writing functions, ummm ... you think that this is void foo (int a, int b, int c, int d, int e) {cout << a << ""; cout << b << ""; cout << c << ""; cout << d << ""; cout << e << ""; is simpler than that? void anotherFoo (int * a, int sz) {for (int i = 0; i <sz; i ++) cout << a [i] << ""; } int arr [5] = {1, 2, 3, 4, 5}; foo (arr [0], arr [1], arr [2], arr [3], arr [4]); A very original idea of ​​simplicity - DreamChild
  • 2
    Do you write in C ++? Use std::vector and do not bother. Assembly inserts - you were not mistaken for a millennium? - VladD
  • In the case of printf (), of course yes, simpler, but, I have a case of func (int z, int d, int f, int ...); and for sane work you have to add int & z = a [0] ... and that’s what I want to get rid of. VladD, if we talk about this method, then I have better options than using a vector. - mikelsv
  • one
    @mikelsv, va_list just hides all the assembly inserts you would write inside yourself. This is probably quite convenient, otherwise you will have to write code designed for a specific compiler (take into account the order of the arguments, the method of their transmission and other low-level magic). Is it necessary? - gecube
  • one
    In short, I have a suggestion - let's get the question of "creating an implementation of a call to functions of an interpreted language" separately in the research section. The question is really interesting and multifaceted. - gecube

4 answers 4

An example with variadric templates in addition to the @gecube answer:

I will say right away that it is better not to use them =) vectors and arrays are better used for postarinka. In general, it is very similar to va_list, so this is not exactly what the vehicle wanted.

 int sum() { // конец рекурсивно-шаблонной вакханалии return 0; } template<typename T, typename... Args> int sum(T value, Args... args) { // функция вида "один элемент и все оставшиеся" // складываем тот элемент, что знаем, и вызываем себя для всех остальных элементов return value + sum(args...); } // вызов функции std::cout << sum(5, 3, 4, 5, 2, 3, 5); 

Try on Ideone

Another option, but with std :: initializer_list <>. Run on Ideone . Looks like that:

 int sum(std::initializer_list<int > intarray) { return std::accumulate(std::begin(intarray), std::end(intarray), 0); } int main() { std::cout << sum({1, 2, 3, 4, 5, 6, 7}) << std::endl; return 0; } 
  • one
    +1 for a high-tech example! Although I would do tail recursion (though I'm not sure if the compiler will use this). - VladD
  • Code: ideone.com/GiLRay - VladD
  • Still, templates are much more reliable than macros and va_lists. Chances to write bjaku, which collapses under certain conditions with them, much less. Give the templates to the masses! - gecube
  • @VladD are you talking about the first example? Syntactically, this is tail recursion. In fact (if I understand correctly) there will just be many instantiated templates (1 for each number of arguments) that will call each other. In the release, they, of course, are in each other. - IronVbif

In any case, without pointers can not do. There are two principal ways to solve the problem:

  1. Passing the pointer and array size to the function: int func (int *arr, int size); The concept is the same as for standard functions of working with memory and strings ( memset , memcpy , etc.)
  2. Using the special ability to create functions with a variable number of arguments. For this you need to use the va_list mechanism. Rubbish rare, but it works. Attention should be paid (special!) To checking that you get as many arguments as you need, otherwise hello destruction of the stack.
  3. If the size of the array is fixed at the top, then you can make a series of functions with a different number of arguments.

like this:

 int func(int a); int func(int a, int b); int func(int a, int b, int c); .... 

The compiler will choose the one you want. Or you can use the default parameter mechanism:

 int func(int a, int b = 0, int c = 0, int d = 0) // и т.д. 

In this case, all unused parameters of the f-tion will be initialized to those values ​​that the programmer will indicate.

Also note that you can use macros or templates to generate similar types of functions.

  • You can also use variadric templates - IronVbif
  • @IronVbif, example in the studio! - gecube
  • The first option is the best, but each element of the array can have its own name and it would be much easier to work with them as with variables. Yes, va_list is hell. Somehow I talked, then I spat and used the third option, by the way I got a normal printf. In principle, I go around the third option. I think to write 50 prototypes, they should definitely be enough. - mikelsv

If I were you, I would have thrust everything into a vector and would not be steamed.

 #define ARRAY_SIZE(arr) ( sizeof(arr) / sizeof arr[0] ) void CallMethodWithVector(const std::vector<int> &refParams) { //do what you want here with your params } void CallerFunction(void) { int arr[15]; // set param values here // ...... std::vector<int> aParams(arr, arr + ARRAY_SIZE(arr) ) CallMethodWithVector(aParams) } 

If the type of parameters is not known in advance, then simply make the CallMethodWithVector template.

It was necessary to do so:

 #include <stdio.h> #include <string.h> // Берем функцию: int test(int a, char *b, double c){ printf("%d %s %f", a, b, c); return 0; } // Делаем прототип: typedef int (*callfunc)(...); // И пишем код: int main(int args, char* arg[]){ // параметры функции, которые хотим передать. double d=11; int str[4]={15, (unsigned int)"text"}; memcpy(str+2, &d, 8); // структура, которая будет полностью скопирована в стек. Если передавать str, то будет передан указатель, а нам нужно передать именно данные. struct efunc_s{ unsigned int a[4]; }; // получаем адрес функции. callfunc cf=(callfunc)test; // Приводим в вид, который будет скопирован в стек. efunc_s &s=*(efunc_s*)&str; // вызываем функцию (*cf)(s); return 0; } 

Under g ++ build with -m32.

UPD. Comments are no longer added.

@VladD , I write under MSVC, everything works here. Under 64 bits it falls. Slightly corrected, but the parameters are passed wrong. Clang will cost. -O3 works in the studio too. The rest of the optimization can be removed for the sake of performance. In principle, if the data type is one, then you can write these 50 functions, but you want to give up the possibility of calling a function with different data types.

@gecube , no, not these external functions. There is an interpreted programming language, you can connect functions to it, say print (string str), a task to call it. Considering that such functions can be many, with their challenge, difficulties begin.

@gecube precisely, Schrödinger's language. That is why I did not use the transfer of the parameters as an array, but I still need a way to call them. Interpretation or compilation, to choose from.

  • Wow, memcpy , cast pointer to unsigned int . Do you want to put a record for the number of UB on a line of code? I wonder if it falls with -O3 ? - VladD
  • No, it works. There seems to be nowhere to fall. I show how it can work, whether to stick your fingers in there to you. ) - mikelsv
  • @mikelsv: you have a pointer aliasing between unrelated types in each line, this is pure UB. - VladD
  • one
    The code is bad. I am sure that any little thing (such as aligment settings) and it will fall. - gecube
  • one
    @mikelsv, explain, after all, what do you want to get in the long run? What specific problem we solve? Still, the same variadic templates look more elegant. - gecube