Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用varargs参数动态调用C函数_C - Fatal编程技术网

使用varargs参数动态调用C函数

使用varargs参数动态调用C函数,c,C,我正在用C编写一个第三方库(在HP/Mercury Loadrunner中),该库允许它的一个函数使用varargs样式的变量大小参数列表。我想调用这个函数,但我不知道前面会有多少个参数 我的一位前任开发了一个函数,该函数在某种程度上起到了作用,但这里的问题是,该函数假设了最坏的情况(超过3000个参数),并为此编写了手动代码 为了说明这一点,下面是代码的开头。我们调用的函数是web\u submit\u data()。它将HTTP发布一组表单数据。此实现是在处理具有任意数量字段的动态生成表单时

我正在用C编写一个第三方库(在HP/Mercury Loadrunner中),该库允许它的一个函数使用varargs样式的变量大小参数列表。我想调用这个函数,但我不知道前面会有多少个参数

我的一位前任开发了一个函数,该函数在某种程度上起到了作用,但这里的问题是,该函数假设了最坏的情况(超过3000个参数),并为此编写了手动代码

为了说明这一点,下面是代码的开头。我们调用的函数是
web\u submit\u data()
。它将HTTP发布一组表单数据。此实现是在处理具有任意数量字段的动态生成表单时实现的。 (从原始索引中清理了一点,原始索引也是手工编码的。)


现在我找到了一个可以工作的外部库(),但我更希望a)完全依赖处理器,b)尝试教Loadrunner如何链接外部源

编辑: 原始函数使用硬编码索引,而不是使用变量。如果结果太不可预测,仍然可以恢复到这一点。然而,由于我不太可能使用不同的编译器或硬件/操作系统来运行它,我怀疑这是否值得

另外:我无法控制web_submit_data()的实现。因此,仅仅把问题降低一个层次并不能解决问题


另一件需要注意的事情是:
web\u submit\u data()
的规范使用一个名为LAST的常量来标记参数列表的末尾。最初的实现没有使用它。想必调用站点会这样做。

在运行时,没有可移植的方法为C中的变量参数函数建立参数列表。有一些依赖于实现,您找到的dyncall库看起来不错,而且可能比大多数库更具可移植性。

注意:代码已经依赖于编译器(尽管可能不依赖于处理器),因为调用
web\u submit\u data
假设过程调用中的参数子表达式是按从左到右的顺序求值的,但C语言未指定参数求值的顺序

请参阅以供参考:


因此,非可移植的解决方案可能不会让情况变得更糟。

您能否重新构造代码,使其不再必要?也许您可以使用传入缓冲区并使其更具确定性:

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);

}

对不起,这实在是太充实了-我妻子叫我进来吃早餐。:-)

用预处理器写一次,不要回头看

#define WEB_SUBMIT_BUFFER(name, val)         \
    do {                                     \
        const int size = 129;                \
        int i = 0;                           \
        int j = 11;                          \
        web_submit_data(&(name)[i++ * size], \
                        &(name)[i++ * size], \
        /* etc ad nauseum */                 \
    } while (0)
或者,如果每个特定调用的参数数量是固定的,则编写一个脚本来生成预处理器定义,以隐藏该调用有多可怕

#define WEB_SUBMIT_BUFFER_32(name, val)      \
    do {                                     \
        const int size = 129;                \
        int i = 0;                           \
        int j = 11;                          \
        web_submit_data(&(name)[i++ * size], \
                        &(name)[i++ * size], \
        /* 32 times */                       \
    } while (0)
#define WEB_SUBMIT_BUFFER_33(name, val) ...
#define WEB_SUBMIT_BUFFER_34(name, val) /* etc */

请注意,您发布的代码示例具有未定义的行为-分隔函数参数的逗号不是序列点(这些逗号不是逗号运算符),因此在函数调用参数列表中多次修改
i
和/或
j
会导致未定义的行为

这并不是说标准中没有规定函数调用参数的求值顺序-因此,即使您使用函数来求值参数(函数调用本身是序列点),对
i
j
进行了修改,您将以不确定的顺序传递指针


另外,我看不出
web\u submit\u data()
如何知道它传递了多少个参数-我看不到最后有一个计数或确定的哨兵参数。但我想你的例子可能就是这样——一个可能没有完整、准确细节的例子。另一方面,这是
web\u submit\u data()
的问题,对吗

由于向采用变量参数的函数传递的参数通常比函数预期的多(请参见脚注#1),因此可以执行以下操作:

// 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]
        );

}


脚注#1:如果你想一想
stdargs.h
中的宏是如何工作的,这一点就很清楚了。然而,我并不认为这种技术符合标准。事实上,在最近的历史中,stackoverflow的答案我已经张贴在我的位置;事实上,我们已经发现本免责声明不符合标准(通常是由时刻警惕的人提出的)。因此,使用此技术的风险由您自己承担,并验证、验证、验证)。

有两种方法可以传递数量可变的参数:传递给接受“…”的函数或传递给接受VAU列表的函数


您不能动态地定义“…”接口的参数数量,但您应该能够为va_list one定义参数数量。谷歌搜索va_start、va_end和va_list。

在CamelBones中,我用来调用objc_msgSend(),这是一个varargs函数。有效。

变长参数基本上只是指向传递给所需函数的一组压缩数据的指针。被调用函数负责解释此压缩数据

架构安全的方法是使用va_列表宏(n-alexander提到过),否则您可能会遇到各种数据类型在内存中填充的问题

设计varargs函数的正确方法是实际上有两个版本,一个版本接受“…”,后者依次提取va_列表并将其传递给接受va_列表的函数。这样,如果需要,您可以动态构造参数,并且可以调用函数的va_列表版本

大多数标准IO函数都有varargs版本:vprintf用于printf,vsprintf用于sprintf。。。你明白了。看看您的库是否实现了一个名为“vweb_submit_data”的函数或类似的函数。如果他们没有,给他们发电子邮件,告诉他们修复他们的库

3000行相同的东西(即使是预处理器诱导的)让我
// 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]
        );

}