Calling a C function with a varargs argument dynamically

前端 未结 10 1384
太阳男子
太阳男子 2020-12-05 11:45

I am programming in C against a third party library (in HP/Mercury Loadrunner) that allows a varargs-style variable size argument list for one of it\'s functions. I want to

相关标签:
10条回答
  • 2020-12-05 11:46

    In CamelBones I use libffi to call objc_msgSend(), which is a varargs function. Works a treat.

    0 讨论(0)
  • 2020-12-05 11:46

    Variable length arguments are basically just a pointer to a bunch of packed data that is passed to the required function. It is the responsibility of the called function to interpret this packed data.

    The architecture safe way to do this is to use the va_list macros (that n-alexander mentioned), otherwise you may run into issues with how various data types are padded in memory.

    The proper way to design varargs functions is to actually have two versions, one that accepts the '...', which in turn extracts the va_list and passes it to a function that takes a va_list. This way you can dynamically construct the arguments if you need to and can instead call the va_list version of the function.

    Most standard IO functions have varargs versions: vprintf for printf, vsprintf for sprintf... you get the idea. See if your library implements a function named "vweb_submit_data" or something to that effect. If they don't, email them and tell them to fix their library.

    3000 lines of the same thing (even if it is preprocessor induced) makes me cringe

    0 讨论(0)
  • 2020-12-05 11:50

    I know this is an old thread, but I just ran across it. The proper way to handle variable length submit form data in LoadRunner is to use a web_custom_request(). You build the name|value pair structure for the variable length of the arguments as a string and pass it in as a part of the function.

    Record the one call as a web_custom_request() and the structure of the argument string for the name|value pairs will become obvious. Simply use any C string handling functions you wish to construct the string in question and include it as a part of the argument list for the web_custom_request().

    0 讨论(0)
  • 2020-12-05 11:51

    Can you restructure your code so that this isn't necessary? Perhaps you could take the incoming buffer and make it more deterministic:

    struct form_field
    {
      char[FIELD_NAME_MAX] name;
      char[FIELD_VALUE_MAX] val;
    };
    
    web_submit_data_buffer_gazillion_items( const char *bufferName, const char *bufferValue)
    {
        /*
          loop over bufferName somehow, either with a known size or terminating record,
          and build an array of form_field records
        */
        //loop
        {
          // build array of records
        }
    
    
        web_submit_data(record_array, array_len);
    
    }
    

    Sorry this couldn't be more fleshed out - my wife called me in for breakfast. :-)

    0 讨论(0)
  • 2020-12-05 11:54

    Since it's generally not a problem to pass more arguments to a function taking variable arguments than the function expects (see footnote #1), you can do something like the following:

    // you didn't give a clear specification of what you want/need, so this 
    // example may not be quite what you want as I've had to guess at
    // some of the specifications. Hopefully the comments will make clear
    // what I may have assumed.
    //
    // NOTE:  while I have compiled this example, I have not tested it,
    //        so there is a distinct possiblity of bugs (particularly
    //        off-by-one errors). Check me on this stuff, please.
    
    // I made these up so I could compile the example
    #define ITEMDATA ((char const*) NULL)
    #define ENDITEM  ((char const*) 0xffffffff)
    
    void web_submit_data_wrapper( const char*bufferName, 
                                  const char* bufferValue, 
                                  size_t headerCount,       // number of header pointers to pass (8 in your example)
                                  size_t itemStartIndex,    // index where items start in the buffers (11 in your example)
                                  size_t itemCount,         // number of items to pass (unspecified in your example)
                                  size_t dataSize )         // size of each header or item (129 in your example)
    {
        // kMaxVarArgs would be 3000 or a gazillion in your case
    
        // size_t const kMaxVarArgs = 20;  // I'd prefer to use this in C++
        #define kMaxVarArgs (20)
    
        typedef char const* char_ptr_t;
        typedef char_ptr_t char_ptr_array_t[kMaxVarArgs];
    
        char_ptr_array_t varargs = {0};
    
        size_t idx = 0;
    
        // build up the array of pararmeters we'll pass to the variable arg list
    
        // first the headers
        while (headerCount--) {
            varargs[idx++] = &bufferName[idx * dataSize];
        }
    
        // mark the end of the header data
        varargs[idx++] = ITEMDATA;
    
        // now the "items"
        while (itemCount--) {
            varargs[idx++] = &bufferName[itemStartIndex * dataSize];
            varargs[idx++] = &bufferValue[itemStartIndex * dataSize];
            varargs[idx++] = ENDITEM;
    
            ++itemStartIndex;
        }
    
        // the thing after the last item 
        // (I'm not sure what this is from your example)
        varargs[idx] = &bufferName[itemStartIndex * dataSize];
    
        // now call the target function - the fact that we're passing more arguments
        //  than necessary should not matter due to the way VA_ARGS are handled 
        //  but see the Footnote in the SO answer for a disclaimer
    
        web_submit_data( 
            varargs[0],
            varargs[1],
            varargs[2],
    
            //... ad nasuem until
    
            varargs[kMaxVarArgs-1]
            );
    
    }
    

    Footnote #1: If you think about how the macros in stdargs.h act this becomes clear. However, I do not claim that this technique would be standards compliant. In fact, in recent history the stackoverflow answers I've posted where I;ve made this disclaimer have in fact been found to be non-standards compliant (usually by the ever vigilant litb). So use this technique at your own risk, and verify, verify, verify).

    0 讨论(0)
  • 2020-12-05 11:58

    There is no portable way to build up an argument list for a variable argument function in C at run time. There are a few implementation-dependent tricks out there, the dyncall library you found looks like a good one and probably more portable than most.

    0 讨论(0)
提交回复
热议问题