Dynamic function calls at runtime (va_list)

故事扮演 提交于 2019-12-11 11:24:54

问题


There is a way in C to obtain a dynamic length argument list with va_list, as described here: http://www.cprogramming.com/tutorial/c/lesson17.html

That quite simple, but most times in C++ not needed. I am currently building a top level wrapper class for encapsulating some Zend functionality.

Anyway, I do need to make a call to such a dynamic function like printf from a normal function dynamically.

I mean the reverse way of the example described above, here is waht I got so war, maybe this explains my idea a little better:

void ZendParams::setRequired( int &Var  )
{
        // save every var pointer to a stack
        // and save the type with it. (if needed, does not seems to be)
        // after call to ZendParams::fetch()
        // the values are stored in the passed variables
        this->_params.push_back( (void*) &Var );
        this->_paramStr.append( 'i' );
}

size_t ZendParams::fetch()
{
        if ( zend_parse_parameters(
                ZEND_NUM_ARGS() TSRMLS_CC, ,
                this->_paramStr.c_str(),
                ...
                ) !== FAILURE)
        {

        }

        return 0;
}

So I want to make the call to zend_parse_parameters dynamically.

The base idea is to add pointer to vars in a list and pass them to the zend function (as reference) dynamically.

I thought there must be a way to do this with va_list , too.

But how?

To get it more simple, I am using this example:

list<int> myList;
myList.push_back(1);
myList.push_back(5);
myList.push_back(10);
myList.push_back(37);
myList.push_back(42);

double function avg( int num, ... )
    va_list arguments;                     
    int sum = 0;

    va_start ( arguments, num );           
    for ( int x = 0; x < num; x++ )        
    {
        sum += va_arg ( arguments, int ); 
    }
    va_end ( arguments );

    return sum / num;      
}

I want to call avg with all numbers I got in the list. I took the example function from the tutorial mentioned above, but it should show up what I mean in a very simple way. However, I can not change the function called, as it is part of the zend framework.

Is there any way in C or C++ to do this?


My 2nd approach:

template <typename... Arguments>
size_t Zend::getMethodParams( string paramStr, Arguments... Args )
{    
        if ( zend_parse_parameters(
                ZEND_NUM_ARGS() TSRMLS_CC, ,
                paramStr.c_str(),
                Args...
                ) == FAILURE)
        {
            return 0;
        }
}

To be called like this (to get the defined 3 Parameters):

string My1stParam;
int My2ndParam;
int My3rdParam;

Zend::getMethodParams<string, int, int>( "sii", &My1stParam, &My2ndParam, &My3rdParam );

I think that should work, but there is one hard issue with that: The zend_parse_parameters function returns 2 values for a string (c-style string!): - a char pointer and - the string length.

So I would either have to call it that way:

char* My1stParam_str;
int My1stParam_length
int My2ndParam;
int My3rdParam;

Zend::getMethodParams<string, int, int>( "sii", &My1stParam_str, &My1stParam_length, &My2ndParam, &My3rdParam );
string My1stParam;
My1stParam.assign(My1stParam_str, My1stParam_length);

Anyway, that was what I wanted to prevent.

Or I would have to modify the list of arguments passed to the zend_parse_parameters function to do these additional steps internally.

I am hoping to be able to call it at least in that way:

string My1stParam;
int My2ndParam;
int My3rdParam;

Zend::getMethodParams<string, int, int>( "sii", &My1stParam, &My2ndParam, &My3rdParam );

So say this clearly: The parameters are known at compile time, but the function call will be very different within all occurrences in the later sourcecode.


回答1:


I found a way around this within the zend framework. I did indeed search for such a solution before, but it seems to be not very good documented ( n.m. already mentoined, that there is no zend internal way like a va_list taking function ).

But there is indeed one!

For everyone else stucking with this problem:

long arg;
zval ***args;
int i, argc = ZEND_NUM_ARGS( );

if (zend_parse_parameters(1 TSRMLS_CC, "l", &arg) == FAILURE) return;

array_init(return_value);
add_index_long(return_value, 0, arg);

if(argc>1) {
    args = (zval ***)emalloc(argc * sizeof(zval **));
    if(zend_get_parameters_array_ex(argc, args) == FAILURE) {
        efree(args);
        return;
    }
    for(i = 1; i < argc; i++) {
        zval_add_ref(args[i]);
        add_index_zval(return_value,i, *args[i]);
    }
    efree(args);
}

That is the solution ;)

This snippet, found on http://docstore.mik.ua/orelly/webprog/php/ch14_07.htm parses all parameters dynamically into the c representation of an PHP array.



来源:https://stackoverflow.com/questions/15988277/dynamic-function-calls-at-runtime-va-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!